From f7a735b7fe557315830a7b741c8b68e088b0f8d1 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 16:31:00 +0800 Subject: [PATCH 001/298] fix(routes): update login route and remove unused routes --- package-lock.json | 4 ++++ routes/auth.php | 2 +- routes/web.php | 53 +---------------------------------------------- 3 files changed, 6 insertions(+), 53 deletions(-) diff --git a/package-lock.json b/package-lock.json index 061a2b4..ad1e058 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,13 @@ { "name": "tailwind-laravel-starter", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "tailwind-laravel-starter", + "version": "1.0.0", + "license": "MIT", "dependencies": { "@tailwindcss/vite": "^4.0.7", "autoprefixer": "^10.4.20", diff --git a/routes/auth.php b/routes/auth.php index 031f43c..c831454 100644 --- a/routes/auth.php +++ b/routes/auth.php @@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Route; Route::middleware('guest')->group(function () { - Route::get('login', Login::class)->name('login'); + Route::get('', Login::class)->name('login'); Route::get('register', Register::class)->name('register'); Route::get('forgot-password', ForgotPassword::class)->name('password.request'); Route::get('reset-password/{token}', ResetPassword::class)->name('password.reset'); diff --git a/routes/web.php b/routes/web.php index dd073f4..4359137 100644 --- a/routes/web.php +++ b/routes/web.php @@ -5,61 +5,10 @@ use App\Livewire\Settings\Profile; use Illuminate\Support\Facades\Route; -Route::get('/', function () { +Route::get('/home', function () { return view('welcome'); })->name('home'); -Route::get('/accordion', function () { - return view('accordion'); -})->name('accordion'); - -Route::get('/carousel', function () { - return view('carousel'); -})->name('carousel'); - -Route::get('/modal', function () { - return view('modal'); -})->name('modal'); - -Route::get('/collapse', function () { - return view('collapse'); -})->name('collapse'); - -Route::get('/dial', function () { - return view('dial'); -})->name('dial'); - -Route::get('/dismiss', function () { - return view('dismiss'); -})->name('dismiss'); - -Route::get('/drawer', function () { - return view('drawer'); -})->name('drawer'); - -Route::get('/dropdown', function () { - return view('dropdown'); -})->name('dropdown'); - -Route::get('/popover', function () { - return view('popover'); -})->name('popover'); - -Route::get('/tooltip', function () { - return view('tooltip'); -})->name('tooltip'); - -Route::get('/input-counter', function () { - return view('input-counter'); -})->name('input-counter'); - -Route::get('/tabs', function () { - return view('tabs'); -})->name('tabs'); - -Route::get('/datepicker', function () { - return view('datepicker'); -})->name('datepicker'); Route::view('dashboard', 'dashboard') ->middleware(['auth', 'verified']) From bef87bc566308c2e37746aba361c54e110ce9a8e Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 16:48:38 +0800 Subject: [PATCH 002/298] setup --- composer.json | 5 +-- composer.lock | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 353e954..2a7611d 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "php": "^8.2", "laravel/framework": "^12.0", "laravel/tinker": "^2.10.1", - "livewire/flux": "^2.0" + "livewire/flux": "^2.0", + "spatie/laravel-permission": "^6.17" }, "require-dev": { "fakerphp/faker": "^1.23", @@ -72,4 +73,4 @@ }, "minimum-stability": "stable", "prefer-stable": true -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index b492374..4739bb4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8bc62669ad1ad3dc46aac03063a35f34", + "content-hash": "cfacc0239ed48259734c39b862d233f6", "packages": [ { "name": "brick/math", @@ -3425,6 +3425,89 @@ ], "time": "2024-04-27T21:32:50+00:00" }, + { + "name": "spatie/laravel-permission", + "version": "6.17.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-permission.git", + "reference": "02ada8f638b643713fa2fb543384738e27346ddb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/02ada8f638b643713fa2fb543384738e27346ddb", + "reference": "02ada8f638b643713fa2fb543384738e27346ddb", + "shasum": "" + }, + "require": { + "illuminate/auth": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/container": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/database": "^8.12|^9.0|^10.0|^11.0|^12.0", + "php": "^8.0" + }, + "require-dev": { + "laravel/passport": "^11.0|^12.0", + "laravel/pint": "^1.0", + "orchestra/testbench": "^6.23|^7.0|^8.0|^9.0|^10.0", + "phpunit/phpunit": "^9.4|^10.1|^11.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\Permission\\PermissionServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "6.x-dev", + "dev-master": "6.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Spatie\\Permission\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Permission handling for Laravel 8.0 and up", + "homepage": "https://github.com/spatie/laravel-permission", + "keywords": [ + "acl", + "laravel", + "permission", + "permissions", + "rbac", + "roles", + "security", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-permission/issues", + "source": "https://github.com/spatie/laravel-permission/tree/6.17.0" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-04-08T15:06:14+00:00" + }, { "name": "symfony/clock", "version": "v7.2.0", From baabc314778455dbd52f520169535336c6ef29cf Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 18:15:34 +0800 Subject: [PATCH 003/298] feat(seeders): add RoleSeeder and UserSeeder classes --- database/seeders/RoleSeeder.php | 17 +++++++++++++++++ database/seeders/UserSeeder.php | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 database/seeders/RoleSeeder.php create mode 100644 database/seeders/UserSeeder.php diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php new file mode 100644 index 0000000..f129660 --- /dev/null +++ b/database/seeders/RoleSeeder.php @@ -0,0 +1,17 @@ + Date: Sat, 19 Apr 2025 18:15:43 +0800 Subject: [PATCH 004/298] feat(controllers): add AdminController, BuyerController, and SellerController classes --- app/Http/Controllers/AdminController.php | 66 +++++++++++++++++++++++ app/Http/Controllers/BuyerController.php | 66 +++++++++++++++++++++++ app/Http/Controllers/SellerController.php | 65 ++++++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 app/Http/Controllers/AdminController.php create mode 100644 app/Http/Controllers/BuyerController.php create mode 100644 app/Http/Controllers/SellerController.php diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php new file mode 100644 index 0000000..46838d4 --- /dev/null +++ b/app/Http/Controllers/AdminController.php @@ -0,0 +1,66 @@ + Date: Sat, 19 Apr 2025 18:15:55 +0800 Subject: [PATCH 005/298] feat(middleware): add role and permission middleware aliases --- bootstrap/app.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bootstrap/app.php b/bootstrap/app.php index 7b162da..7479a17 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -12,6 +12,11 @@ ) ->withMiddleware(function (Middleware $middleware) { // + $middleware->alias([ + 'role' => \Spatie\Permission\Middleware\RoleMiddleware::class, + 'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class, + 'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class, + ]); }) ->withExceptions(function (Exceptions $exceptions) { // From 93ed5c6efad5b93fd5ed728d32cc99e1d82eb146 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 18:16:13 +0800 Subject: [PATCH 006/298] fix(routes): correct login route path and add role-based dashboard routes --- routes/auth.php | 2 +- routes/web.php | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/routes/auth.php b/routes/auth.php index c831454..5504685 100644 --- a/routes/auth.php +++ b/routes/auth.php @@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Route; Route::middleware('guest')->group(function () { - Route::get('', Login::class)->name('login'); + Route::get('/login', Login::class)->name('login'); Route::get('register', Register::class)->name('register'); Route::get('forgot-password', ForgotPassword::class)->name('password.request'); Route::get('reset-password/{token}', ResetPassword::class)->name('password.reset'); diff --git a/routes/web.php b/routes/web.php index 4359137..44c1795 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,12 +1,15 @@ route('login'); })->name('home'); @@ -22,4 +25,16 @@ Route::get('settings/appearance', Appearance::class)->name('settings.appearance'); }); +Route::middleware(['auth', 'role:admin'])->group(function () { + Route::get('/admin/dashboard', [AdminController::class, 'index'])->name('admin.dashboard'); +}); + +Route::middleware(['auth', 'role:seller'])->group(function () { + Route::get('/seller/dashboard', [SellerController::class, 'index'])->name('seller.dashboard'); +}); + +Route::middleware(['auth', 'role:buyer'])->group(function () { + Route::get('/buyer/dashboard', [BuyerController::class, 'index'])->name('buyer.dashboard'); +}); + require __DIR__.'/auth.php'; From 8342946cabdad6275b805320563b196114923fc7 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 18:16:29 +0800 Subject: [PATCH 007/298] feat(dashboards): add separate dashboard views for admin, buyer, and seller roles --- resources/views/admin/dashboard.blade.php | 0 resources/views/buyer/dashboard.blade.php | 0 .../components/layouts/app/sidebar.blade.php | 21 +++++++++---------- resources/views/seller/dashboard.blade.php | 3 +++ 4 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 resources/views/admin/dashboard.blade.php create mode 100644 resources/views/buyer/dashboard.blade.php create mode 100644 resources/views/seller/dashboard.blade.php diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php new file mode 100644 index 0000000..e69de29 diff --git a/resources/views/buyer/dashboard.blade.php b/resources/views/buyer/dashboard.blade.php new file mode 100644 index 0000000..e69de29 diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index e8678e1..b8b0958 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -13,22 +13,21 @@ - {{ __('Dashboard') }} + @hasrole('admin') + {{ __('Admin Dashboard') }} + @endhasrole + @hasrole('seller') + {{ __('Seller Dashboard') }} + @endhasrole + @hasrole('customer') + {{ __('Customer Dashboard') }} + @endhasrole + {{-- {{ __('Dashboard') }} --}} - - - {{ __('Repository') }} - - - - {{ __('Documentation') }} - - - + + \ No newline at end of file From e4447756742cf8f99898ba166e9dfcb89aed5e22 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 18:16:39 +0800 Subject: [PATCH 008/298] feat(models): add Product model and integrate Spatie roles in User model --- app/Models/Product.php | 10 ++ app/Models/User.php | 3 +- config/permission.php | 202 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 app/Models/Product.php create mode 100644 config/permission.php diff --git a/app/Models/Product.php b/app/Models/Product.php new file mode 100644 index 0000000..7fb8e6b --- /dev/null +++ b/app/Models/Product.php @@ -0,0 +1,10 @@ + */ - use HasFactory, Notifiable; + use HasFactory, Notifiable, HasRoles; /** * The attributes that are mass assignable. diff --git a/config/permission.php b/config/permission.php new file mode 100644 index 0000000..8e84e9d --- /dev/null +++ b/config/permission.php @@ -0,0 +1,202 @@ + [ + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * Eloquent model should be used to retrieve your permissions. Of course, it + * is often just the "Permission" model but you may use whatever you like. + * + * The model you want to use as a Permission model needs to implement the + * `Spatie\Permission\Contracts\Permission` contract. + */ + + 'permission' => Spatie\Permission\Models\Permission::class, + + /* + * When using the "HasRoles" trait from this package, we need to know which + * Eloquent model should be used to retrieve your roles. Of course, it + * is often just the "Role" model but you may use whatever you like. + * + * The model you want to use as a Role model needs to implement the + * `Spatie\Permission\Contracts\Role` contract. + */ + + 'role' => Spatie\Permission\Models\Role::class, + + ], + + 'table_names' => [ + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'roles' => 'roles', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your permissions. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'permissions' => 'permissions', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your models permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_permissions' => 'model_has_permissions', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your models roles. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_roles' => 'model_has_roles', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'role_has_permissions' => 'role_has_permissions', + ], + + 'column_names' => [ + /* + * Change this if you want to name the related pivots other than defaults + */ + 'role_pivot_key' => null, // default 'role_id', + 'permission_pivot_key' => null, // default 'permission_id', + + /* + * Change this if you want to name the related model primary key other than + * `model_id`. + * + * For example, this would be nice if your primary keys are all UUIDs. In + * that case, name this `model_uuid`. + */ + + 'model_morph_key' => 'model_id', + + /* + * Change this if you want to use the teams feature and your related model's + * foreign key is other than `team_id`. + */ + + 'team_foreign_key' => 'team_id', + ], + + /* + * When set to true, the method for checking permissions will be registered on the gate. + * Set this to false if you want to implement custom logic for checking permissions. + */ + + 'register_permission_check_method' => true, + + /* + * When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered + * this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated + * NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it. + */ + 'register_octane_reset_listener' => false, + + /* + * Events will fire when a role or permission is assigned/unassigned: + * \Spatie\Permission\Events\RoleAttached + * \Spatie\Permission\Events\RoleDetached + * \Spatie\Permission\Events\PermissionAttached + * \Spatie\Permission\Events\PermissionDetached + * + * To enable, set to true, and then create listeners to watch these events. + */ + 'events_enabled' => false, + + /* + * Teams Feature. + * When set to true the package implements teams using the 'team_foreign_key'. + * If you want the migrations to register the 'team_foreign_key', you must + * set this to true before doing the migration. + * If you already did the migration then you must make a new migration to also + * add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions' + * (view the latest version of this package's migration file) + */ + + 'teams' => false, + + /* + * The class to use to resolve the permissions team id + */ + 'team_resolver' => \Spatie\Permission\DefaultTeamResolver::class, + + /* + * Passport Client Credentials Grant + * When set to true the package will use Passports Client to check permissions + */ + + 'use_passport_client_credentials' => false, + + /* + * When set to true, the required permission names are added to exception messages. + * This could be considered an information leak in some contexts, so the default + * setting is false here for optimum safety. + */ + + 'display_permission_in_exception' => false, + + /* + * When set to true, the required role names are added to exception messages. + * This could be considered an information leak in some contexts, so the default + * setting is false here for optimum safety. + */ + + 'display_role_in_exception' => false, + + /* + * By default wildcard permission lookups are disabled. + * See documentation to understand supported syntax. + */ + + 'enable_wildcard_permission' => false, + + /* + * The class to use for interpreting wildcard permissions. + * If you need to modify delimiters, override the class and specify its name here. + */ + // 'permission.wildcard_permission' => Spatie\Permission\WildcardPermission::class, + + /* Cache-specific settings */ + + 'cache' => [ + + /* + * By default all permissions are cached for 24 hours to speed up performance. + * When permissions or roles are updated the cache is flushed automatically. + */ + + 'expiration_time' => \DateInterval::createFromDateString('24 hours'), + + /* + * The cache key used to store all permissions. + */ + + 'key' => 'spatie.permission.cache', + + /* + * You may optionally indicate a specific cache driver to use for permission and + * role caching using any of the `store` drivers listed in the cache.php config + * file. Using 'default' here means to use the `default` set in cache.php. + */ + + 'store' => 'default', + ], +]; From 8abd55dd38dda1a413c2e89931015ac66f366073 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 18:16:46 +0800 Subject: [PATCH 009/298] feat(auth): implement role-based redirection after login and assign default role on registration --- app/Livewire/Auth/Login.php | 15 ++++++++++++++- app/Livewire/Auth/Register.php | 10 ++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/app/Livewire/Auth/Login.php b/app/Livewire/Auth/Login.php index 9925f63..e4fd667 100644 --- a/app/Livewire/Auth/Login.php +++ b/app/Livewire/Auth/Login.php @@ -13,6 +13,7 @@ use Livewire\Component; #[Layout('components.layouts.auth')] + class Login extends Component { #[Validate('required|string|email')] @@ -43,7 +44,19 @@ public function login(): void RateLimiter::clear($this->throttleKey()); Session::regenerate(); - $this->redirectIntended(default: route('dashboard', absolute: false), navigate: true); + // Redirect based on role + $user = Auth::user(); + + if ($user->hasRole('admin')) { + $this->redirectIntended(default: route('admin.dashboard'), navigate: true); + } elseif ($user->hasRole('seller')) { + $this->redirectIntended(default: route('seller.dashboard'), navigate: true); + } elseif ($user->hasRole('buyer')) { + $this->redirectIntended(default: route('buyer.dashboard'), navigate: true); + } else { + // Default fallback (optional) + $this->redirectIntended(default: route('dashboard'), navigate: true); + } } /** diff --git a/app/Livewire/Auth/Register.php b/app/Livewire/Auth/Register.php index 8541536..79dc408 100644 --- a/app/Livewire/Auth/Register.php +++ b/app/Livewire/Auth/Register.php @@ -34,10 +34,16 @@ public function register(): void $validated['password'] = Hash::make($validated['password']); - event(new Registered(($user = User::create($validated)))); + // Create the user + $user = User::create($validated); + + // Assign the default role as 'buyer' + $user->assignRole('buyer'); + + event(new Registered($user)); Auth::login($user); - $this->redirect(route('dashboard', absolute: false), navigate: true); + $this->redirect(route('buyer.dashboard', absolute: false), navigate: true); } } From fd172c70de8b32aed678e24a4d6d08d8945cf7a4 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 18:16:54 +0800 Subject: [PATCH 010/298] feat(seeders): add RoleSeeder and UserSeeder to create roles and assign them to users --- database/seeders/RoleSeeder.php | 6 ++++++ database/seeders/UserSeeder.php | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php index f129660..fbbf5b1 100644 --- a/database/seeders/RoleSeeder.php +++ b/database/seeders/RoleSeeder.php @@ -4,6 +4,7 @@ use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; +use Spatie\Permission\Models\Role; class RoleSeeder extends Seeder { @@ -13,5 +14,10 @@ class RoleSeeder extends Seeder public function run(): void { // + // Create roles + Role::create(['name' => 'admin']); + Role::create(['name' => 'seller']); + Role::create(['name' => 'buyer']); + } } diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php index 9887e55..8364147 100644 --- a/database/seeders/UserSeeder.php +++ b/database/seeders/UserSeeder.php @@ -2,6 +2,7 @@ namespace Database\Seeders; +use App\Models\User; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; @@ -13,5 +14,22 @@ class UserSeeder extends Seeder public function run(): void { // + + + // Create an admin user + $admin = User::create([ + 'name' => 'Admin User', + 'email' => 'admin@example.com', + 'password' => bcrypt('password'), // Use a secure password + ]); + $admin->assignRole('admin'); + + // Create a seller user + $seller = User::create([ + 'name' => 'Seller User', + 'email' => 'seller@example.com', + 'password' => bcrypt('password'), // Use a secure password + ]); + $seller->assignRole('seller'); } } From 92656d80165d3aa3a8e72cb891cf33ff1108431d Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 18:17:10 +0800 Subject: [PATCH 011/298] feat(migrations): create permission and role tables with relationships --- ..._04_19_083407_create_permission_tables.php | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 database/migrations/2025_04_19_083407_create_permission_tables.php diff --git a/database/migrations/2025_04_19_083407_create_permission_tables.php b/database/migrations/2025_04_19_083407_create_permission_tables.php new file mode 100644 index 0000000..70a120f --- /dev/null +++ b/database/migrations/2025_04_19_083407_create_permission_tables.php @@ -0,0 +1,140 @@ +engine('InnoDB'); + $table->bigIncrements('id'); // permission id + $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) + $table->string('guard_name'); // For MyISAM use string('guard_name', 25); + $table->timestamps(); + + $table->unique(['name', 'guard_name']); + }); + + Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) { + // $table->engine('InnoDB'); + $table->bigIncrements('id'); // role id + if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing + $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable(); + $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index'); + } + $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) + $table->string('guard_name'); // For MyISAM use string('guard_name', 25); + $table->timestamps(); + if ($teams || config('permission.testing')) { + $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']); + } else { + $table->unique(['name', 'guard_name']); + } + }); + + Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) { + $table->unsignedBigInteger($pivotPermission); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index'); + + $table->foreign($pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } else { + $table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } + + }); + + Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) { + $table->unsignedBigInteger($pivotRole); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index'); + + $table->foreign($pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } else { + $table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } + }); + + Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) { + $table->unsignedBigInteger($pivotPermission); + $table->unsignedBigInteger($pivotRole); + + $table->foreign($pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + + $table->foreign($pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + + $table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary'); + }); + + app('cache') + ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null) + ->forget(config('permission.cache.key')); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + $tableNames = config('permission.table_names'); + + if (empty($tableNames)) { + throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); + } + + Schema::drop($tableNames['role_has_permissions']); + Schema::drop($tableNames['model_has_roles']); + Schema::drop($tableNames['model_has_permissions']); + Schema::drop($tableNames['roles']); + Schema::drop($tableNames['permissions']); + } +}; From 3a04500b139650e449ce5202f66fc6e71b0b5509 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 18:17:21 +0800 Subject: [PATCH 012/298] feat(products): add ProductController and migration for products table --- .../Controllers/Seller/ProductController.php | 89 +++++++++++++++++++ ...025_04_19_100614_create_products_table.php | 32 +++++++ 2 files changed, 121 insertions(+) create mode 100644 app/Http/Controllers/Seller/ProductController.php create mode 100644 database/migrations/2025_04_19_100614_create_products_table.php diff --git a/app/Http/Controllers/Seller/ProductController.php b/app/Http/Controllers/Seller/ProductController.php new file mode 100644 index 0000000..a206310 --- /dev/null +++ b/app/Http/Controllers/Seller/ProductController.php @@ -0,0 +1,89 @@ +validate([ + 'name' => 'required|string|max:255', + 'description' => 'required|string', + 'price' => 'required|numeric|min:0', + 'stock' => 'required|integer|min:0', + 'image' => 'nullable|image|max:2048', + ]); + + if ($request->hasFile('image')) { + $validated['image'] = $request->file('image')->store('products', 'public'); + } + + Product::create($validated); + + return redirect()->route('seller.products.index')->with('success', 'Product created successfully.'); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Product $product) + { + return view('seller.products.edit', compact('product')); + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, Product $product) + { + $validated = $request->validate([ + 'name' => 'required|string|max:255', + 'description' => 'required|string', + 'price' => 'required|numeric|min:0', + 'stock' => 'required|integer|min:0', + 'image' => 'nullable|image|max:2048', + ]); + + if ($request->hasFile('image')) { + $validated['image'] = $request->file('image')->store('products', 'public'); + } + + $product->update($validated); + + return redirect()->route('seller.products.index')->with('success', 'Product updated successfully.'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Product $product) + { + $product->delete(); + + return redirect()->route('seller.products.index')->with('success', 'Product deleted successfully.'); + } +} diff --git a/database/migrations/2025_04_19_100614_create_products_table.php b/database/migrations/2025_04_19_100614_create_products_table.php new file mode 100644 index 0000000..ff134ae --- /dev/null +++ b/database/migrations/2025_04_19_100614_create_products_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('name'); + $table->text('description'); + $table->decimal('price', 10, 2); + $table->integer('stock'); + $table->string('image')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('products'); + } +}; From 268a1a1632fea4e94c2c5f3ec7e997bbcbf404f5 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 18:17:31 +0800 Subject: [PATCH 013/298] Remove unused Blade view files for datepicker, dial, dismiss, drawer, dropdown, input counter, modal, popover, tabs, and tooltip components to streamline the codebase. --- resources/views/accordion.blade.php | 55 ----------------- resources/views/carousel.blade.php | 56 ----------------- resources/views/collapse.blade.php | 39 ------------ resources/views/datepicker.blade.php | 16 ----- resources/views/dial.blade.php | 57 ----------------- resources/views/dismiss.blade.php | 81 ------------------------- resources/views/drawer.blade.php | 35 ----------- resources/views/dropdown.blade.php | 30 --------- resources/views/input-counter.blade.php | 31 ---------- resources/views/modal.blade.php | 46 -------------- resources/views/popover.blade.php | 19 ------ resources/views/tabs.blade.php | 38 ------------ resources/views/tooltip.blade.php | 14 ----- 13 files changed, 517 deletions(-) delete mode 100644 resources/views/accordion.blade.php delete mode 100644 resources/views/carousel.blade.php delete mode 100644 resources/views/collapse.blade.php delete mode 100644 resources/views/datepicker.blade.php delete mode 100644 resources/views/dial.blade.php delete mode 100644 resources/views/dismiss.blade.php delete mode 100644 resources/views/drawer.blade.php delete mode 100644 resources/views/dropdown.blade.php delete mode 100644 resources/views/input-counter.blade.php delete mode 100644 resources/views/modal.blade.php delete mode 100644 resources/views/popover.blade.php delete mode 100644 resources/views/tabs.blade.php delete mode 100644 resources/views/tooltip.blade.php diff --git a/resources/views/accordion.blade.php b/resources/views/accordion.blade.php deleted file mode 100644 index 68cb9d3..0000000 --- a/resources/views/accordion.blade.php +++ /dev/null @@ -1,55 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-

- -

- -

- -

- -

- -

- -
-
-@endsection diff --git a/resources/views/carousel.blade.php b/resources/views/carousel.blade.php deleted file mode 100644 index 3bee10c..0000000 --- a/resources/views/carousel.blade.php +++ /dev/null @@ -1,56 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- -
-@endsection diff --git a/resources/views/collapse.blade.php b/resources/views/collapse.blade.php deleted file mode 100644 index 83e7541..0000000 --- a/resources/views/collapse.blade.php +++ /dev/null @@ -1,39 +0,0 @@ -@extends('layouts.app') - -@section('content') - - - -@endsection diff --git a/resources/views/datepicker.blade.php b/resources/views/datepicker.blade.php deleted file mode 100644 index 5e9591e..0000000 --- a/resources/views/datepicker.blade.php +++ /dev/null @@ -1,16 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- -
-
- -
- -
- -
-@endsection diff --git a/resources/views/dial.blade.php b/resources/views/dial.blade.php deleted file mode 100644 index 3edf6fa..0000000 --- a/resources/views/dial.blade.php +++ /dev/null @@ -1,57 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- - -
-@endsection diff --git a/resources/views/dismiss.blade.php b/resources/views/dismiss.blade.php deleted file mode 100644 index 007ba13..0000000 --- a/resources/views/dismiss.blade.php +++ /dev/null @@ -1,81 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- - - - - -
-@endsection diff --git a/resources/views/drawer.blade.php b/resources/views/drawer.blade.php deleted file mode 100644 index 0e686a3..0000000 --- a/resources/views/drawer.blade.php +++ /dev/null @@ -1,35 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- - -
- -
- - -
-
Info
- - -

Supercharge your hiring by taking advantage of our limited-time sale for Flowbite Docs + Job Board. Unlimited access to over 190K top-ranked candidates and the #1 design job board.

- -
- -
-@endsection diff --git a/resources/views/dropdown.blade.php b/resources/views/dropdown.blade.php deleted file mode 100644 index e41c26d..0000000 --- a/resources/views/dropdown.blade.php +++ /dev/null @@ -1,30 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- - - - - - -
-@endsection diff --git a/resources/views/input-counter.blade.php b/resources/views/input-counter.blade.php deleted file mode 100644 index 0563ee7..0000000 --- a/resources/views/input-counter.blade.php +++ /dev/null @@ -1,31 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- -
- -
- - -
- - Bedrooms -
- -
-

Please select the number of bedrooms.

-
- -
-@endsection diff --git a/resources/views/modal.blade.php b/resources/views/modal.blade.php deleted file mode 100644 index b039061..0000000 --- a/resources/views/modal.blade.php +++ /dev/null @@ -1,46 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- - - - - - -
-@endsection diff --git a/resources/views/popover.blade.php b/resources/views/popover.blade.php deleted file mode 100644 index 57f1e88..0000000 --- a/resources/views/popover.blade.php +++ /dev/null @@ -1,19 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- - - - - -
-@endsection diff --git a/resources/views/tabs.blade.php b/resources/views/tabs.blade.php deleted file mode 100644 index 158ebc9..0000000 --- a/resources/views/tabs.blade.php +++ /dev/null @@ -1,38 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- -
-
    - - - -
  • - -
  • -
-
-
- - - - -
- -
-@endsection diff --git a/resources/views/tooltip.blade.php b/resources/views/tooltip.blade.php deleted file mode 100644 index b50cabd..0000000 --- a/resources/views/tooltip.blade.php +++ /dev/null @@ -1,14 +0,0 @@ -@extends('layouts.app') - -@section('content') -
- - - - - -
-@endsection From 61facc543e631372d1ce7546682febe1f7211a11 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 19:06:33 +0800 Subject: [PATCH 014/298] feat(products): update ProductController to return products view and add category validation; create products view with modal for adding new products --- .../Controllers/Seller/ProductController.php | 5 +- app/Models/Product.php | 8 + ...025_04_19_100614_create_products_table.php | 1 + resources/views/seller/products.blade.php | 142 ++++++++++++++++++ 4 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 resources/views/seller/products.blade.php diff --git a/app/Http/Controllers/Seller/ProductController.php b/app/Http/Controllers/Seller/ProductController.php index a206310..3ae9f91 100644 --- a/app/Http/Controllers/Seller/ProductController.php +++ b/app/Http/Controllers/Seller/ProductController.php @@ -14,7 +14,7 @@ class ProductController extends Controller public function index() { $products = Product::all(); - return view('seller.products.index', compact('products')); + return view('seller.products', compact('products')); } /** @@ -35,6 +35,7 @@ public function store(Request $request) 'description' => 'required|string', 'price' => 'required|numeric|min:0', 'stock' => 'required|integer|min:0', + 'category' => 'required|string|max:255', 'image' => 'nullable|image|max:2048', ]); @@ -44,7 +45,7 @@ public function store(Request $request) Product::create($validated); - return redirect()->route('seller.products.index')->with('success', 'Product created successfully.'); + return redirect()->back()->with('success', 'Product created successfully.'); } /** diff --git a/app/Models/Product.php b/app/Models/Product.php index 7fb8e6b..6a91228 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -7,4 +7,12 @@ class Product extends Model { // + protected $fillable = [ + 'name', + 'description', + 'price', + 'stock', + 'category', + 'image', + ]; } diff --git a/database/migrations/2025_04_19_100614_create_products_table.php b/database/migrations/2025_04_19_100614_create_products_table.php index ff134ae..6105312 100644 --- a/database/migrations/2025_04_19_100614_create_products_table.php +++ b/database/migrations/2025_04_19_100614_create_products_table.php @@ -15,6 +15,7 @@ public function up(): void $table->id(); $table->string('name'); $table->text('description'); + $table->text('category'); $table->decimal('price', 10, 2); $table->integer('stock'); $table->string('image')->nullable(); diff --git a/resources/views/seller/products.blade.php b/resources/views/seller/products.blade.php new file mode 100644 index 0000000..fadf5f7 --- /dev/null +++ b/resources/views/seller/products.blade.php @@ -0,0 +1,142 @@ + +
+

My Products

+ + +
+ +
+ + + + +
+ + + + + + + + + + + + + @foreach ($products as $product) + + + + + + + + + + + @endforeach + +
+ Product name + + Description + + Price + + Stock + + +
+ {{ $product->name }} + + {{ $product->description }} + + ${{ $product->price }} + + {{ $product->stock }} + + Edit + + +
+ @csrf + @method('DELETE') + +
+
+
+ + @section('modals') + + @endsection +
+
\ No newline at end of file From de51021098ef4182844c053b895035ccb394bf6c Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 19:06:51 +0800 Subject: [PATCH 015/298] feat(sidebar): add 'My Products' link for seller role in sidebar navigation --- resources/views/components/layouts/app/sidebar.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index b8b0958..c07a41c 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -18,6 +18,7 @@ @endhasrole @hasrole('seller') {{ __('Seller Dashboard') }} + {{ __('My Products') }} @endhasrole @hasrole('customer') {{ __('Customer Dashboard') }} @@ -125,7 +126,6 @@ class="flex h-full w-full items-center justify-center rounded-lg bg-neutral-200 {{ $slot }} - @fluxScripts From 2ebfda6d363466634c119010916694071a30e212 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 19:06:56 +0800 Subject: [PATCH 016/298] fix(head): correct placement of Flowbite JavaScript inclusion in head.blade.php --- resources/views/partials/head.blade.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/views/partials/head.blade.php b/resources/views/partials/head.blade.php index 6badc7e..d37e7a5 100644 --- a/resources/views/partials/head.blade.php +++ b/resources/views/partials/head.blade.php @@ -5,6 +5,7 @@ - + + @vite(['resources/css/app.css', 'resources/js/app.js']) @fluxAppearance From 0ffca03da35f353ef64755ab7d38cb85b49f282a Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 19 Apr 2025 19:07:06 +0800 Subject: [PATCH 017/298] fix(routes): remove unused routes and streamline the routing configuration --- routes/web.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/routes/web.php b/routes/web.php index 44c1795..11f9dcd 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,6 +3,7 @@ use App\Http\Controllers\AdminController; use App\Http\Controllers\SellerController; use App\Http\Controllers\BuyerController; +use App\Http\Controllers\Seller\ProductController; use App\Livewire\Settings\Appearance; use App\Livewire\Settings\Password; use App\Livewire\Settings\Profile; @@ -29,8 +30,12 @@ Route::get('/admin/dashboard', [AdminController::class, 'index'])->name('admin.dashboard'); }); -Route::middleware(['auth', 'role:seller'])->group(function () { - Route::get('/seller/dashboard', [SellerController::class, 'index'])->name('seller.dashboard'); + + +Route::middleware(['auth', 'role:seller'])->prefix('seller')->name('seller.')->group(function () { + Route::get('/dashboard', [SellerController::class, 'index'])->name('dashboard'); + + Route::resource('products', ProductController::class); }); Route::middleware(['auth', 'role:buyer'])->group(function () { From f105d271b646491637238aafc7f065fa05decc0e Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sun, 20 Apr 2025 00:01:27 +0800 Subject: [PATCH 018/298] Add customer layout, product view, and section components - Created a new customer layout in `customer-layout.blade.php` for consistent styling across customer pages. - Added a section component in `section.blade.php` for reusable layout structure. - Implemented a product view page in `product-view.blade.php` to display product details, including images, pricing, and add-to-cart functionality. - Enhanced the seller's product management page in `products.blade.php` with modals for editing products and improved error handling. - Updated routes in `web.php` to include cart management functionalities for buyers. --- app/Http/Controllers/Buyer/CartController.php | 90 ++ app/Http/Controllers/BuyerController.php | 4 +- .../Controllers/Seller/ProductController.php | 8 +- app/Models/Order.php | 33 + app/Models/Product.php | 6 + app/Providers/AppServiceProvider.php | 6 + app/View/Components/customer-layout.php | 26 + app/View/Components/section.php | 26 + ...025_04_19_100614_create_products_table.php | 1 + .../2025_04_19_153612_create_orders_table.php | 32 + resources/views/buyer/dashboard.blade.php | 881 ++++++++++++++++++ resources/views/cart/index.blade.php | 117 +++ .../layouts/customer-layout.blade.php | 305 ++++++ resources/views/components/section.blade.php | 3 + .../views/product/product-view.blade.php | 77 ++ resources/views/seller/products.blade.php | 247 +++-- routes/web.php | 11 +- 17 files changed, 1799 insertions(+), 74 deletions(-) create mode 100644 app/Http/Controllers/Buyer/CartController.php create mode 100644 app/Models/Order.php create mode 100644 app/View/Components/customer-layout.php create mode 100644 app/View/Components/section.php create mode 100644 database/migrations/2025_04_19_153612_create_orders_table.php create mode 100644 resources/views/cart/index.blade.php create mode 100644 resources/views/components/layouts/customer-layout.blade.php create mode 100644 resources/views/components/section.blade.php create mode 100644 resources/views/product/product-view.blade.php diff --git a/app/Http/Controllers/Buyer/CartController.php b/app/Http/Controllers/Buyer/CartController.php new file mode 100644 index 0000000..274bc36 --- /dev/null +++ b/app/Http/Controllers/Buyer/CartController.php @@ -0,0 +1,90 @@ +product_id); + + $cart = Session::get('cart', []); + + // Check if the product is already in the cart + if (isset($cart[$product->id])) { + $cart[$product->id]['quantity'] += $request->quantity; + } else { + $cart[$product->id] = [ + 'name' => $product->name, + 'price' => $product->price, + 'quantity' => $request->quantity, + 'image' => $product->image, + ]; + } + + Session::put('cart', $cart); + + return redirect()->back()->with('success', 'Product added to cart successfully!'); + } + + public function checkout(Request $request) + { + $cart = Session::get('cart', []); + + if (empty($cart)) { + return redirect()->back()->with('error', 'Your cart is empty!'); + } + + // Group items by seller + $groupedItems = []; + foreach ($cart as $id => $item) { + $product = Product::findOrFail($id); + $groupedItems[$product->seller_id][] = $item; + } + + // Create orders for each seller + foreach ($groupedItems as $sellerId => $items) { + $total = array_sum(array_map(fn($item) => $item['price'] * $item['quantity'], $items)); + + Order::create([ + 'buyer_id' => Auth::id(), + 'seller_id' => $sellerId, + 'items' => $items, + 'total' => $total, + 'status' => 'Pending', + ]); + } + + // Clear the cart + Session::forget('cart'); + + return redirect()->back()->with('success', 'Order placed successfully!'); + } + + public function remove($id) + { + $cart = Session::get('cart', []); + + if (isset($cart[$id])) { + unset($cart[$id]); + Session::put('cart', $cart); + } + + return redirect()->back()->with('success', 'Item removed from cart.'); + } +} diff --git a/app/Http/Controllers/BuyerController.php b/app/Http/Controllers/BuyerController.php index 7065c87..eaca74d 100644 --- a/app/Http/Controllers/BuyerController.php +++ b/app/Http/Controllers/BuyerController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Models\Product; use Illuminate\Http\Request; class BuyerController extends Controller @@ -12,8 +13,9 @@ class BuyerController extends Controller public function index() { // + $products = Product::all(); // Fetch all products from the database - return view('buyer.dashboard'); + return view('buyer.dashboard',compact('products')); // Pass the products to the view } /** diff --git a/app/Http/Controllers/Seller/ProductController.php b/app/Http/Controllers/Seller/ProductController.php index 3ae9f91..3205c28 100644 --- a/app/Http/Controllers/Seller/ProductController.php +++ b/app/Http/Controllers/Seller/ProductController.php @@ -42,7 +42,8 @@ public function store(Request $request) if ($request->hasFile('image')) { $validated['image'] = $request->file('image')->store('products', 'public'); } - + // Automatically assign the authenticated seller's ID + $validated['seller_id'] = auth()->id(); Product::create($validated); return redirect()->back()->with('success', 'Product created successfully.'); @@ -87,4 +88,9 @@ public function destroy(Product $product) return redirect()->route('seller.products.index')->with('success', 'Product deleted successfully.'); } + + public function show(Product $product) + { + return view('product.product-view', compact('product')); + } } diff --git a/app/Models/Order.php b/app/Models/Order.php new file mode 100644 index 0000000..46aba28 --- /dev/null +++ b/app/Models/Order.php @@ -0,0 +1,33 @@ + 'array', // Cast items JSON to array + ]; + + public function buyer() + { + return $this->belongsTo(User::class, 'buyer_id'); + } + + public function seller() + { + return $this->belongsTo(User::class, 'seller_id'); + } +} diff --git a/app/Models/Product.php b/app/Models/Product.php index 6a91228..7e2d45d 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -10,9 +10,15 @@ class Product extends Model protected $fillable = [ 'name', 'description', + 'seller_id', 'price', 'stock', 'category', 'image', ]; + + public function seller() + { + return $this->belongsTo(User::class, 'seller_id'); + } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 452e6b6..24cc4cb 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,6 +2,8 @@ namespace App\Providers; +use Illuminate\Support\Facades\Session; +use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -20,5 +22,9 @@ public function register(): void public function boot(): void { // + View::composer('*', function ($view) { + $cart = Session::get('cart', []); + $view->with('cart', $cart); + }); } } diff --git a/app/View/Components/customer-layout.php b/app/View/Components/customer-layout.php new file mode 100644 index 0000000..806d123 --- /dev/null +++ b/app/View/Components/customer-layout.php @@ -0,0 +1,26 @@ +integer('stock'); $table->string('image')->nullable(); $table->timestamps(); + $table->foreignId('seller_id')->constrained('users')->onDelete('cascade'); }); } diff --git a/database/migrations/2025_04_19_153612_create_orders_table.php b/database/migrations/2025_04_19_153612_create_orders_table.php new file mode 100644 index 0000000..8fe2d2e --- /dev/null +++ b/database/migrations/2025_04_19_153612_create_orders_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('buyer_id')->constrained('users')->onDelete('cascade'); + $table->foreignId('seller_id')->constrained('users')->onDelete('cascade'); + $table->json('items'); // Store cart items as JSON + $table->decimal('total', 10, 2); + $table->string('status')->default('Pending'); // e.g., Pending, Completed + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('orders'); + } +}; diff --git a/resources/views/buyer/dashboard.blade.php b/resources/views/buyer/dashboard.blade.php index e69de29..c1db8f0 100644 --- a/resources/views/buyer/dashboard.blade.php +++ b/resources/views/buyer/dashboard.blade.php @@ -0,0 +1,881 @@ + +
+
+
+

+ Limited Time Offer!
Up to 50% OFF!

+

Don't + Wait - Limited Stock at Unbeatable Prices!

+ Shop + Now +
+ +
+ +
+ + +
+
+ +
+
+ +

Electronics

+
+
+ + + +
+
+ +
+ @foreach ($products as $product) +
+ + +
+ + + {{ $product->name }} + +
+
+ + + + + + + + + +
+ +

4.9

+

(879)

+
+ + {{--
    +
  • + +

    Shipping Today

    +
  • + +
  • + +

    Best Price

    +
  • +
--}} + +
+

RM{{ $product->price }}

+ + +
+
+
+ @endforeach +
+
+ +
+
+ + + +
+ +
+
\ No newline at end of file diff --git a/resources/views/cart/index.blade.php b/resources/views/cart/index.blade.php new file mode 100644 index 0000000..e4e8b73 --- /dev/null +++ b/resources/views/cart/index.blade.php @@ -0,0 +1,117 @@ + +
+
+

Shopping Cart

+ +
+
+ @if (empty($cart)) +

Your cart is empty.

+ @else +
+ @foreach ($cart as $id => $item) +
+
+ + + {{ $item['name'] }} + + + +
+
+ + + +
+
+

${{ $item['price'] + * $item['quantity'] }}

+
+
+ + +
+ {{ + $item['name'] }} + +
+
+ @csrf + @method('DELETE') + +
+
+
+
+
+ @endforeach +
+ @endif +
+ + +
+
+

Order summary

+ +
+
+
+
Total Items
+
{{ count($cart) }} +
+
+ +
+
Total
+
+ ${{ array_sum(array_map(fn($item) => $item['price'] * $item['quantity'], $cart)) + }} +
+
+
+
+
+ @csrf + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/resources/views/components/layouts/customer-layout.blade.php b/resources/views/components/layouts/customer-layout.blade.php new file mode 100644 index 0000000..780a46c --- /dev/null +++ b/resources/views/components/layouts/customer-layout.blade.php @@ -0,0 +1,305 @@ +
+ +
+ + + + + + + Customer Site + @include('partials.head') + + + + + + {{-- --}} + + {{ $slot }} + + + + + + + \ No newline at end of file diff --git a/resources/views/components/section.blade.php b/resources/views/components/section.blade.php new file mode 100644 index 0000000..3e91bc1 --- /dev/null +++ b/resources/views/components/section.blade.php @@ -0,0 +1,3 @@ +
+ {{ $slot }} +
\ No newline at end of file diff --git a/resources/views/product/product-view.blade.php b/resources/views/product/product-view.blade.php new file mode 100644 index 0000000..9524c4f --- /dev/null +++ b/resources/views/product/product-view.blade.php @@ -0,0 +1,77 @@ + + @if (session('success')) +
+ {{ session('success') }} +
+ @endif +
+
+
+ +
+ {{ $product->name }} + +
+ + +
+

+ {{ $product->name }} +

+
+

+ RM{{ $product->price }} +

+
+
+ @for ($i = 1; $i <= 5; $i++) + @endfor +
+

+ ({{ $product->rating }}) +

+ + {{ $product->reviews_count }} Reviews + +
+
+ + +
+
+ @csrf + + + +
+
+ +
+ +

+ {{ $product->description }} +

+
+
+
+
+
\ No newline at end of file diff --git a/resources/views/seller/products.blade.php b/resources/views/seller/products.blade.php index fadf5f7..ad94bcb 100644 --- a/resources/views/seller/products.blade.php +++ b/resources/views/seller/products.blade.php @@ -1,14 +1,169 @@

My Products

+ @if (session('success')) + + @endif - + @if ($errors->any()) + + @endif +
+ class="block text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" + type="button"> + Add Product + +
+ + +
+ + + + + + + + + + + + + + @foreach ($products as $product) + + + + + + + + + + + + + @endforeach + +
ImageProduct NameDescriptionPriceStock
+ @if ($product->image) + {{ $product->name }} + @else + No Image + @endif + + {{ $product->name }} + + {{ $product->description }} + + ${{ $product->price }} + + {{ $product->stock }} + + + + + + + +
+ @csrf + @method('DELETE') + +
+
@@ -25,7 +180,8 @@ class="hidden fixed top-0 left-0 right-0 z-50 flex items-center justify-center w
- -
- - - - - - - - - - - - - @foreach ($products as $product) - - - - - - - - - - - @endforeach - -
- Product name - - Description - - Price - - Stock - - -
- {{ $product->name }} - - {{ $product->description }} - - ${{ $product->price }} - - {{ $product->stock }} - - Edit - - -
- @csrf - @method('DELETE') - -
-
-
- - @section('modals') - - @endsection
\ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 11f9dcd..40e2ca0 100644 --- a/routes/web.php +++ b/routes/web.php @@ -4,6 +4,7 @@ use App\Http\Controllers\SellerController; use App\Http\Controllers\BuyerController; use App\Http\Controllers\Seller\ProductController; +use App\Http\Controllers\Buyer\CartController; use App\Livewire\Settings\Appearance; use App\Livewire\Settings\Password; use App\Livewire\Settings\Profile; @@ -35,11 +36,19 @@ Route::middleware(['auth', 'role:seller'])->prefix('seller')->name('seller.')->group(function () { Route::get('/dashboard', [SellerController::class, 'index'])->name('dashboard'); - Route::resource('products', ProductController::class); + Route::resource('products', ProductController::class)->except(['show']); }); Route::middleware(['auth', 'role:buyer'])->group(function () { + Route::post('/cart/add', [CartController::class, 'add'])->name('cart.add'); + Route::get('/cart', [CartController::class, 'index'])->name('cart.index'); + Route::delete('/cart/remove/{id}', [CartController::class, 'remove'])->name('cart.remove'); + Route::post('/cart/checkout', [CartController::class, 'checkout'])->name('cart.checkout'); Route::get('/buyer/dashboard', [BuyerController::class, 'index'])->name('buyer.dashboard'); }); +Route::middleware(['auth'])->group(function () { + Route::get('/products/{product}', [ProductController::class, 'show'])->name('products.show'); +}); + require __DIR__.'/auth.php'; From c3f6e8f5e989c1f5bef794b7d4ae87ca074fe951 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 11:49:50 +0800 Subject: [PATCH 019/298] feat(reviews): implement review system with CRUD operations, modal for adding reviews, and display of average ratings --- .../Controllers/Buyer/ReviewController.php | 39 ++++++++ .../Controllers/Seller/ProductController.php | 6 +- app/Models/Product.php | 5 + app/Models/Review.php | 29 ++++++ app/View/Components/ReviewCard.php | 26 ++++++ app/View/Components/ReviewProgressBar.php | 57 ++++++++++++ ...2025_04_20_043621_create_reviews_table.php | 32 +++++++ public/js/add-review.js | 63 +++++++++++++ .../views/components/review-card.blade.php | 23 +++++ .../views/components/review-modal.blade.php | 92 +++++++++++++++++++ .../components/review-progress-bar.blade.php | 39 ++++++++ .../views/product/product-view.blade.php | 46 +++++++++- routes/web.php | 9 ++ 13 files changed, 460 insertions(+), 6 deletions(-) create mode 100644 app/Http/Controllers/Buyer/ReviewController.php create mode 100644 app/Models/Review.php create mode 100644 app/View/Components/ReviewCard.php create mode 100644 app/View/Components/ReviewProgressBar.php create mode 100644 database/migrations/2025_04_20_043621_create_reviews_table.php create mode 100644 public/js/add-review.js create mode 100644 resources/views/components/review-card.blade.php create mode 100644 resources/views/components/review-modal.blade.php create mode 100644 resources/views/components/review-progress-bar.blade.php diff --git a/app/Http/Controllers/Buyer/ReviewController.php b/app/Http/Controllers/Buyer/ReviewController.php new file mode 100644 index 0000000..d323c21 --- /dev/null +++ b/app/Http/Controllers/Buyer/ReviewController.php @@ -0,0 +1,39 @@ +validate([ + 'title' => 'required|string', + 'content' => 'required|string|max:1000', + 'rating' => 'required|integer|min:1|max:5', + ]); + + $validated['product_id'] = $product->id; + $validated['user_id'] = Auth::id(); + + Review::create($validated); + + return redirect()->back()->with('success', 'Review added successfully.'); + } + + public function destroy(Review $review) + { + if ($review->user_id !== Auth::id()) { + return redirect()->back()->with('error', 'You are not authorized to delete this review.'); + } + + $review->delete(); + + return redirect()->back()->with('success', 'Review deleted successfully.'); + } +} diff --git a/app/Http/Controllers/Seller/ProductController.php b/app/Http/Controllers/Seller/ProductController.php index 3205c28..070b851 100644 --- a/app/Http/Controllers/Seller/ProductController.php +++ b/app/Http/Controllers/Seller/ProductController.php @@ -14,6 +14,7 @@ class ProductController extends Controller public function index() { $products = Product::all(); + // $avgRating = $product->reviews()->avg('rating') ?? 0 ; return view('seller.products', compact('products')); } @@ -91,6 +92,9 @@ public function destroy(Product $product) public function show(Product $product) { - return view('product.product-view', compact('product')); + // Calculate the average rating for the product + $averageRating = $product->reviews()->avg('rating') ?? 0; + + return view('product.product-view', compact('product','averageRating')); } } diff --git a/app/Models/Product.php b/app/Models/Product.php index 7e2d45d..a4bf233 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -21,4 +21,9 @@ public function seller() { return $this->belongsTo(User::class, 'seller_id'); } + + public function reviews() + { + return $this->hasMany(Review::class); + } } diff --git a/app/Models/Review.php b/app/Models/Review.php new file mode 100644 index 0000000..d645bbf --- /dev/null +++ b/app/Models/Review.php @@ -0,0 +1,29 @@ +belongsTo(Product::class); + } + + public function user() + { + return $this->belongsTo(User::class); + } +} diff --git a/app/View/Components/ReviewCard.php b/app/View/Components/ReviewCard.php new file mode 100644 index 0000000..0ea1e82 --- /dev/null +++ b/app/View/Components/ReviewCard.php @@ -0,0 +1,26 @@ +calculateRatings(); + } + + /** + * Calculate the ratings breakdown and overall rating for the product. + */ + private function calculateRatings(): void + { + $product = Product::findOrFail($this->productId); + $this->totalReviews = $product->reviews->count(); + $this->averageRating = $this->totalReviews > 0 + ? round($product->reviews->avg('rating'), 2) + : 0; + + $this->ratings = collect(range(1, 5))->map(function ($rating) use ($product) { + $reviewCount = $product->reviews->where('rating', $rating)->count(); + $percentage = $this->totalReviews > 0 ? ($reviewCount / $this->totalReviews) * 100 : 0; + + return [ + 'rating' => $rating, + 'reviewCount' => $reviewCount, + 'percentage' => round($percentage), + ]; + }); + } + + /** + * Get the view / contents that represent the component. + */ + public function render(): View|string + { + return view('components.review-progress-bar', [ + 'ratings' => $this->ratings, + 'averageRating' => $this->averageRating, + 'totalReviews' => $this->totalReviews, + ]); + } +} diff --git a/database/migrations/2025_04_20_043621_create_reviews_table.php b/database/migrations/2025_04_20_043621_create_reviews_table.php new file mode 100644 index 0000000..81b8a54 --- /dev/null +++ b/database/migrations/2025_04_20_043621_create_reviews_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('product_id')->constrained()->onDelete('cascade'); + $table->foreignId('user_id')->constrained()->onDelete('cascade'); + $table->text('title'); + $table->text('content')->nullable(); + $table->integer('rating')->unsigned(); // Rating out of 5 + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('reviews'); + } +}; diff --git a/public/js/add-review.js b/public/js/add-review.js new file mode 100644 index 0000000..0171c5c --- /dev/null +++ b/public/js/add-review.js @@ -0,0 +1,63 @@ +$(document).ready(function () { + // Open the modal + $('[data-modal-toggle="review-modal"]').on('click', function () { + $('#review-modal').toggleClass('hidden'); + }); + + // Close the modal + $('.close-modal').on('click', function () { + $('#review-modal').addClass('hidden'); + }); + + // Handle star rating click + let selectedRating = 0; + $('.rating-star').on('click', function () { + selectedRating = $(this).data('value'); + console.log(selectedRating); + $('.rating-star').each(function () { + if ($(this).data('value') <= selectedRating) { + $(this).addClass('text-yellow-300').removeClass('text-gray-300 dark:text-gray-500'); + } else { + $(this).addClass('text-gray-300 dark:text-gray-500').removeClass('text-yellow-300'); + } + }); + + $('#total_selected_rating').text(selectedRating + '.0 out of 5'); + }); + + // Get the store URL from the modal's data attribute + const storeUrl = $('#review-modal').data('store-url'); + + // Handle form submission + $('#review-form').on('submit', function (e) { + e.preventDefault(); + + if (selectedRating === 0) { + alert('Please select a rating.'); + return; + } + + const formData = { + title: $('#title').val(), + rating: selectedRating, + content: $('#content').val(), + _token: $('meta[name="csrf-token"]').attr('content') + }; + console.log($('#title').val()); + console.log($('#content').val()); + + + $.ajax({ + url: storeUrl, + method: 'POST', + data: formData, + success: function (response) { + alert('Review submitted successfully!'); + location.reload(); // Reload the page to show the new review + }, + error: function (error) { + alert(error.responseJSON.message || 'An error occurred while submitting the review.'); + } + }); + }); +}); \ No newline at end of file diff --git a/resources/views/components/review-card.blade.php b/resources/views/components/review-card.blade.php new file mode 100644 index 0000000..babada6 --- /dev/null +++ b/resources/views/components/review-card.blade.php @@ -0,0 +1,23 @@ +@props(['rating', 'username', 'createdAt', 'content','title']) + +
+
+
+ @for ($i = 1; $i <= 5; $i++) + + @endfor +
+ +
+

{{ $username }}

+

{{ $createdAt }}

+
+
+ +
+

{{ $title }}

+

{{ $content }}

+
+
\ No newline at end of file diff --git a/resources/views/components/review-modal.blade.php b/resources/views/components/review-modal.blade.php new file mode 100644 index 0000000..1adcf0b --- /dev/null +++ b/resources/views/components/review-modal.blade.php @@ -0,0 +1,92 @@ + + \ No newline at end of file diff --git a/resources/views/components/review-progress-bar.blade.php b/resources/views/components/review-progress-bar.blade.php new file mode 100644 index 0000000..5f1968a --- /dev/null +++ b/resources/views/components/review-progress-bar.blade.php @@ -0,0 +1,39 @@ +@props(['ratings', 'averageRating']) + +
+ +
+

+ {{ $averageRating }} out of 5 +

+ +
+ + +
+ @foreach ($ratings as $ratingData) +
+

+ {{ $ratingData['rating'] }} +

+ +
+
+
+ + {{ $ratingData['reviewCount'] }} + + +
+ @endforeach +
+
\ No newline at end of file diff --git a/resources/views/product/product-view.blade.php b/resources/views/product/product-view.blade.php index 9524c4f..4234b8d 100644 --- a/resources/views/product/product-view.blade.php +++ b/resources/views/product/product-view.blade.php @@ -4,7 +4,7 @@ {{ session('success') }} @endif -
+
@@ -27,16 +27,16 @@
@for ($i = 1; $i <= 5; $i++) - @endfor + @endfor

- ({{ $product->rating }}) + ({{ number_format($averageRating, 1)}})

@@ -73,5 +73,41 @@ class="ml-4 text-white bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:ri
-
+ + + +
+

Reviews

+ + + +
+ @if ($product->reviews->isEmpty()) +

No reviews yet. Be the first to review this product!

+ @else + @foreach ($product->reviews as $review) + + @endforeach + @endif + +
+
+
+ + + + @include('components.review-modal') + + @push('scripts') + + + + @endpush + \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 40e2ca0..b1bdba9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -5,6 +5,7 @@ use App\Http\Controllers\BuyerController; use App\Http\Controllers\Seller\ProductController; use App\Http\Controllers\Buyer\CartController; +use App\Http\Controllers\Buyer\ReviewController; use App\Livewire\Settings\Appearance; use App\Livewire\Settings\Password; use App\Livewire\Settings\Profile; @@ -39,9 +40,13 @@ Route::resource('products', ProductController::class)->except(['show']); }); + Route::middleware(['auth', 'role:buyer'])->group(function () { Route::post('/cart/add', [CartController::class, 'add'])->name('cart.add'); Route::get('/cart', [CartController::class, 'index'])->name('cart.index'); + + + Route::delete('/cart/remove/{id}', [CartController::class, 'remove'])->name('cart.remove'); Route::post('/cart/checkout', [CartController::class, 'checkout'])->name('cart.checkout'); Route::get('/buyer/dashboard', [BuyerController::class, 'index'])->name('buyer.dashboard'); @@ -49,6 +54,10 @@ Route::middleware(['auth'])->group(function () { Route::get('/products/{product}', [ProductController::class, 'show'])->name('products.show'); + + // REVIEWS + Route::post('/products/{product}/reviews', [ReviewController::class, 'store'])->name('reviews.store'); + Route::delete('/reviews/{review}', [ReviewController::class, 'destroy'])->name('reviews.destroy'); }); require __DIR__.'/auth.php'; From 028ab1643b36e7d4fbe944cabe85c0e0a4f2a15f Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 11:50:00 +0800 Subject: [PATCH 020/298] feat(cart): implement add to cart functionality with form submission --- resources/views/buyer/dashboard.blade.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/resources/views/buyer/dashboard.blade.php b/resources/views/buyer/dashboard.blade.php index c1db8f0..493237a 100644 --- a/resources/views/buyer/dashboard.blade.php +++ b/resources/views/buyer/dashboard.blade.php @@ -245,13 +245,21 @@ class="mx-auto grid max-w-screen-xl grid-cols-2 gap-8 text-gray-500 dark:text-gr

RM{{ $product->price }}

- - +
+ @csrf + + + + +
From e5bb543b13c61a29e1ccbbb8c8bb07c5755ac8de Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 11:50:49 +0800 Subject: [PATCH 021/298] add csrf token, jquery, and fontawesome for icon also @stack for push any scripts --- resources/views/partials/head.blade.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resources/views/partials/head.blade.php b/resources/views/partials/head.blade.php index d37e7a5..a475f51 100644 --- a/resources/views/partials/head.blade.php +++ b/resources/views/partials/head.blade.php @@ -1,11 +1,14 @@ - + {{ $title ?? 'Laravel' }} + + +@stack('scripts') @vite(['resources/css/app.css', 'resources/js/app.js']) @fluxAppearance From f87330d9333b3d454520d64b214c346269a1eebe Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 11:51:17 +0800 Subject: [PATCH 022/298] navigation for seller to view their products --- resources/views/seller/products.blade.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/resources/views/seller/products.blade.php b/resources/views/seller/products.blade.php index ad94bcb..9fc5405 100644 --- a/resources/views/seller/products.blade.php +++ b/resources/views/seller/products.blade.php @@ -38,6 +38,7 @@ class="block text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline Stock + @@ -83,6 +84,12 @@ class="w-16 h-16 object-cover rounded"> + + +
+ View Product + + From 3914bf0ee368f3898a8bee61860b49986f092c85 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:34:23 +0800 Subject: [PATCH 023/298] feat(dependencies): add simple-datatables package to enhance data table functionality --- package-lock.json | 23 +++++++++++++++++++++++ package.json | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index ad1e058..6bd48a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "concurrently": "^9.0.1", "flowbite": "^3.1.2", "laravel-vite-plugin": "^1.0", + "simple-datatables": "^10.0.0", "tailwindcss": "^4.0.7", "vite": "^6.0" }, @@ -1215,6 +1216,12 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -1245,6 +1252,12 @@ "node": ">=0.10" } }, + "node_modules/diff-dom": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/diff-dom/-/diff-dom-5.1.4.tgz", + "integrity": "sha512-TSEaVdVGictY1KHg7VpVw2nuM02YKC9C8/qBkGiCnkiAybVbu1zQTMj2/dnVLRO7Z62UsqzHGpXweiOj5/jaZg==", + "license": "LGPL-3.0" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2129,6 +2142,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-datatables": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/simple-datatables/-/simple-datatables-10.0.0.tgz", + "integrity": "sha512-Pqzld1ixWz2/dbA3ZB/3m78elfolzbiC0+aBuugj+bF70Yk35J0p8qwrOpaAfSe/8II9WV+nKJ5CYDOeJVx5mw==", + "license": "LGPL-3.0", + "dependencies": { + "dayjs": "^1.11.10", + "diff-dom": "^5.1.3" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", diff --git a/package.json b/package.json index e34ac51..22fddbe 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "contributors": [ "Zoltán Szőgyényi (https://x.com/zoltanszogyenyi)" ], - "author": "Bergside Inc.", + "author": "Bergside Inc.", "type": "module", "scripts": { "build": "vite build", @@ -21,6 +21,7 @@ "concurrently": "^9.0.1", "flowbite": "^3.1.2", "laravel-vite-plugin": "^1.0", + "simple-datatables": "^10.0.0", "tailwindcss": "^4.0.7", "vite": "^6.0" }, From be88425c9bf8b132c24a7687367f6ece627bac61 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:35:03 +0800 Subject: [PATCH 024/298] admin seller management page --- app/Http/Controllers/AdminController.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 46838d4..bd17d4f 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -2,7 +2,9 @@ namespace App\Http\Controllers; +use App\Models\User; use Illuminate\Http\Request; +use Spatie\Permission\Models\Role; class AdminController extends Controller { @@ -63,4 +65,12 @@ public function destroy(string $id) { // } + + public function showManageSeller() + { + // Show the manage seller view + // You can pass any data to the view if needed + $sellers = User::role('seller')->get(); // Fetch all sellers + return view('admin.manage-seller',compact('sellers')); + } } From c69eec26af4d4b71610916e68284efcab3b2bad7 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:35:28 +0800 Subject: [PATCH 025/298] view customer account profile --- app/Http/Controllers/BuyerController.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/Http/Controllers/BuyerController.php b/app/Http/Controllers/BuyerController.php index eaca74d..abf9dec 100644 --- a/app/Http/Controllers/BuyerController.php +++ b/app/Http/Controllers/BuyerController.php @@ -65,4 +65,15 @@ public function destroy(string $id) { // } + + public function showAccount() + { + $user = auth()->user(); + $ordersCount = $user->orders()->count() ?? 0; + $reviewsCount = $user->reviews()->count() ?? 0; + $latestOrders = $user->orders()->latest()->take(5)->get(); + + // Logic to show the buyer's account details + return view('buyer.account-profile', compact('user', 'ordersCount', 'reviewsCount', 'latestOrders')); // Return the view for the buyer's account + } } From accd546f90ce09367cde495506681c204d15024a Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:35:37 +0800 Subject: [PATCH 026/298] tambah rating --- app/Models/Product.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Models/Product.php b/app/Models/Product.php index a4bf233..71ff7a0 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -15,6 +15,7 @@ class Product extends Model 'stock', 'category', 'image', + 'rating' ]; public function seller() From dee9a0235bc83cb60aae18286d7bf6a2bc151754 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:35:51 +0800 Subject: [PATCH 027/298] tambah relation --- app/Models/User.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/Models/User.php b/app/Models/User.php index 87d3e54..99fa424 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -58,4 +58,14 @@ public function initials(): string ->map(fn (string $name) => Str::of($name)->substr(0, 1)) ->implode(''); } + + public function orders() + { + return $this->hasMany(Order::class,'buyer_id'); + } + + public function reviews() + { + return $this->hasMany(Review::class); + } } From d2a952c3bc01382227db32e14485c4744c4666ed Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:36:25 +0800 Subject: [PATCH 028/298] component header untuk bahagian admin dan seller for consistency --- app/View/Components/DashboardHeader.php | 26 +++++++++++++++++++ .../components/dashboard-header.blade.php | 3 +++ 2 files changed, 29 insertions(+) create mode 100644 app/View/Components/DashboardHeader.php create mode 100644 resources/views/components/dashboard-header.blade.php diff --git a/app/View/Components/DashboardHeader.php b/app/View/Components/DashboardHeader.php new file mode 100644 index 0000000..6b1cd68 --- /dev/null +++ b/app/View/Components/DashboardHeader.php @@ -0,0 +1,26 @@ + + {{ $slot }} + \ No newline at end of file From 92bf1786045fc7b075a1f6cef08b28736c9a30f0 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:36:45 +0800 Subject: [PATCH 029/298] component dropdown item --- app/View/Components/DropdownItem.php | 26 +++++++++++++++++++ .../views/components/dropdown-item.blade.php | 24 +++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 app/View/Components/DropdownItem.php create mode 100644 resources/views/components/dropdown-item.blade.php diff --git a/app/View/Components/DropdownItem.php b/app/View/Components/DropdownItem.php new file mode 100644 index 0000000..9d73f74 --- /dev/null +++ b/app/View/Components/DropdownItem.php @@ -0,0 +1,26 @@ + []]) + +
  • + + +
  • \ No newline at end of file From 475003c79812e17fe7b15a6e250f60b068e3bd53 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:37:08 +0800 Subject: [PATCH 030/298] sidebar item untuk nampak kemas sikit code --- app/View/Components/SidebarItem.php | 26 +++++++++++++++++++ .../views/components/sidebar-item.blade.php | 17 ++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 app/View/Components/SidebarItem.php create mode 100644 resources/views/components/sidebar-item.blade.php diff --git a/app/View/Components/SidebarItem.php b/app/View/Components/SidebarItem.php new file mode 100644 index 0000000..5fb648e --- /dev/null +++ b/app/View/Components/SidebarItem.php @@ -0,0 +1,26 @@ + false, 'type' => 'link']) + +
  • + @if ($type === 'submit') + + @else + + + {{ $label }} + + @endif +
  • \ No newline at end of file From 654bf38d193f03ef439a29df661b45a31865c63f Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:37:28 +0800 Subject: [PATCH 031/298] tukar jadi component supaya tak serabut codenya --- app/View/Components/OrderList.php | 26 ++++++++ .../views/components/order-list.blade.php | 59 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 app/View/Components/OrderList.php create mode 100644 resources/views/components/order-list.blade.php diff --git a/app/View/Components/OrderList.php b/app/View/Components/OrderList.php new file mode 100644 index 0000000..b15d440 --- /dev/null +++ b/app/View/Components/OrderList.php @@ -0,0 +1,26 @@ + []]) + +
    +
    +
    Order ID:
    +
    + {{ $orderId }} +
    +
    + +
    +
    Date:
    +
    {{ $date }}
    +
    + +
    +
    Price:
    +
    ${{ number_format($price, 2) }}
    +
    + +
    +
    Status:
    +
    + + {{ $status }} +
    +
    + + {{--
    + + +
    --}} +
    \ No newline at end of file From 2c78afb77fca95d1597912777fdcbb6244c47144 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:37:54 +0800 Subject: [PATCH 032/298] buat theme pink --- resources/css/app.css | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/css/app.css b/resources/css/app.css index e21e3ae..94bbf3c 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -29,16 +29,16 @@ --color-zinc-900: #171717; --color-zinc-950: #0a0a0a; - --color-accent: var(--color-neutral-800); - --color-accent-content: var(--color-neutral-800); + --color-accent: var(--color-pink-600); + --color-accent-content: var(--color-pink-600); --color-accent-foreground: var(--color-white); } @layer theme { .dark { - --color-accent: var(--color-white); - --color-accent-content: var(--color-white); - --color-accent-foreground: var(--color-neutral-800); + --color-accent: var(--color-pink-600); + --color-accent-content: var(--color-pink-400); + --color-accent-foreground: var(--color-white); } } From 0ed4266cdf2b16077d28ce6c6e2373b72bddf750 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:38:26 +0800 Subject: [PATCH 033/298] dashboard admin masih kosong --- resources/views/admin/dashboard.blade.php | 218 ++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php index e69de29..3538f80 100644 --- a/resources/views/admin/dashboard.blade.php +++ b/resources/views/admin/dashboard.blade.php @@ -0,0 +1,218 @@ + + Admin Dashboard + + + {{-- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + Company Name + + + + Ticker + + + + Stock Price + + + + Market Capitalization + +
    Apple Inc.AAPL$192.58$3.04T
    Microsoft CorporationMSFT$340.54$2.56T
    Alphabet Inc.GOOGL$134.12$1.72T
    Amazon.com Inc.AMZN$138.01$1.42T
    NVIDIA CorporationNVDA$466.19$1.16T
    Tesla Inc.TSLA$255.98$811.00B
    Meta Platforms Inc.META$311.71$816.00B
    Berkshire Hathaway Inc.BRK.B$354.08$783.00B
    TSMCTSM$103.51$538.00B
    UnitedHealth Group Incorporated + UNH$501.96$466.00B
    Johnson & JohnsonJNJ$172.85$452.00B
    JPMorgan Chase & Co.JPM$150.23$431.00B
    Visa Inc.V$246.39$519.00B
    Eli Lilly and CompanyLLY$582.97$552.00B
    Walmart Inc.WMT$159.67$429.00B
    Samsung Electronics Co., Ltd. + 005930.KS$70.22$429.00B
    Procter & Gamble Co.PG$156.47$366.00B
    Nestlé S.A.NESN.SW$120.51$338.00B
    Roche Holding AGROG.SW$296.00$317.00B
    Chevron CorporationCVX$160.92$310.00B
    LVMH Moët Hennessy Louis Vuitton + MC.PA$956.60$478.00B
    Pfizer Inc.PFE$35.95$200.00B
    Novo Nordisk A/SNVO$189.15$443.00B
    PepsiCo, Inc.PEP$182.56$311.00B
    ASML Holding N.V.ASML$665.72$273.00B
    The Coca-Cola CompanyKO$61.37$265.00B
    Oracle CorporationORCL$118.36$319.00B
    Merck & Co., Inc.MRK$109.12$276.00B
    Broadcom Inc.AVGO$861.80$356.00B
    Mastercard IncorporatedMA$421.44$396.00B
    --}} + + +
    \ No newline at end of file From 59215f06790c8334c376171c7f556b6031bfe1dd Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:38:55 +0800 Subject: [PATCH 034/298] page untuk admin manage seller --- resources/views/admin/manage-seller.blade.php | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 resources/views/admin/manage-seller.blade.php diff --git a/resources/views/admin/manage-seller.blade.php b/resources/views/admin/manage-seller.blade.php new file mode 100644 index 0000000..9b7343c --- /dev/null +++ b/resources/views/admin/manage-seller.blade.php @@ -0,0 +1,34 @@ + + Manage Seller + + +
    + + + + + + + + + @foreach ($sellers as $seller) + + + + + @endforeach + + +
    + + Name + + + + Ticker + +
    {{ $seller->name }}{{ $seller->email }}
    +
    + + +
    \ No newline at end of file From 40e0bba85664ad230b6a3fe9c428a1a29e6e542c Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:39:13 +0800 Subject: [PATCH 035/298] account profile untuk customer --- .../views/buyer/account-profile.blade.php | 670 ++++++++++++++++++ 1 file changed, 670 insertions(+) create mode 100644 resources/views/buyer/account-profile.blade.php diff --git a/resources/views/buyer/account-profile.blade.php b/resources/views/buyer/account-profile.blade.php new file mode 100644 index 0000000..62c95f9 --- /dev/null +++ b/resources/views/buyer/account-profile.blade.php @@ -0,0 +1,670 @@ + +
    +
    + +

    My Account

    + +
    +
    + +

    Orders made

    + {{ $ordersCount }} + {{-- + + 10.3% + + --}} +
    +
    + +

    Reviews added

    + {{ $reviewsCount }} + {{-- + + 8.6% + --}} + +
    +
    +
    +
    +
    +
    + Helene avatar +
    +

    + {{ $user->name }}

    +
    +
    +
    +
    Email Address
    +
    {{ $user->email }}
    +
    +
    +
    Home Address
    +
    + + 2 Miles Drive, NJ 071, New York, United States of America +
    +
    +
    +
    Delivery Address
    +
    + + 9th St. PATH Station, New York, United States of America +
    +
    +
    +
    +
    +
    Phone Number
    +
    +1234 567 890 / +12 345 678
    +
    + {{--
    +
    Payment Methods
    +
    +
    + + +
    +
    +
    +

    Visa ending in 7658 +

    +

    Expiry 10/2024

    +
    +
    +
    +
    --}} +
    +
    + +
    +
    +

    Latest orders

    + {{-- Loop Order here --}} + @if ($latestOrders->isEmpty()) +

    No orders found.

    + @else + @foreach ($latestOrders as $order) + + @endforeach + + @endif + +
    +
    + + + + +
    +
    \ No newline at end of file From 6598e087b315c4daaaa9a86dac2798cafb069022 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:39:37 +0800 Subject: [PATCH 036/298] tukar kepada dynamic page --- resources/views/buyer/dashboard.blade.php | 53 ++++++----------------- 1 file changed, 14 insertions(+), 39 deletions(-) diff --git a/resources/views/buyer/dashboard.blade.php b/resources/views/buyer/dashboard.blade.php index 493237a..937ac49 100644 --- a/resources/views/buyer/dashboard.blade.php +++ b/resources/views/buyer/dashboard.blade.php @@ -104,7 +104,10 @@ class="mx-auto grid max-w-screen-xl grid-cols-2 gap-8 text-gray-500 dark:text-gr - + + + +
    @@ -121,26 +124,11 @@ class="mx-auto grid max-w-screen-xl grid-cols-2 gap-8 text-gray-500 dark:text-gr Home -
  • -
    - - Products -
    -
  • -
  • -
    - - Electronics -
    -
  • Electronics

    + {{-- fILTTERS --}}
    +
    @foreach ($products as $product) @@ -198,33 +187,19 @@ class="mx-auto grid max-w-screen-xl grid-cols-2 gap-8 text-gray-500 dark:text-gr
    - {{ $product->name }} + {{ $product->name }}
    - - - - - - - - - + @for ($i = 1; $i <= 5; $i++) + + @endfor
    -

    4.9

    -

    (879)

    +

    + {{ number_format($product->reviews->avg('rating'), 1) }} +

    +

    ({{ $product->reviews->count() }})

    {{--
      From c36cba576ca0ab3002e59a9edb41a1445eabf1a8 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:40:10 +0800 Subject: [PATCH 037/298] tukar class --- resources/views/components/review-modal.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/components/review-modal.blade.php b/resources/views/components/review-modal.blade.php index 1adcf0b..b2e4e65 100644 --- a/resources/views/components/review-modal.blade.php +++ b/resources/views/components/review-modal.blade.php @@ -81,7 +81,7 @@ class="font-semibold">Click to upload or drag and drop

    From 1857147653035c7aef81f04b7ca42055ce4aafc1 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:40:28 +0800 Subject: [PATCH 038/298] refactor this section --- resources/views/components/review-progress-bar.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/components/review-progress-bar.blade.php b/resources/views/components/review-progress-bar.blade.php index 5f1968a..52ed99b 100644 --- a/resources/views/components/review-progress-bar.blade.php +++ b/resources/views/components/review-progress-bar.blade.php @@ -7,7 +7,7 @@ {{ $averageRating }} out of 5

    From e0585ad395f5a143c14604d14db7c35df316ae5b Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:40:41 +0800 Subject: [PATCH 039/298] sadas --- .../views/components/layouts/app.blade.php | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/resources/views/components/layouts/app.blade.php b/resources/views/components/layouts/app.blade.php index 3d15107..ad1a014 100644 --- a/resources/views/components/layouts/app.blade.php +++ b/resources/views/components/layouts/app.blade.php @@ -1,5 +1,17 @@ - - {{ $slot }} - - + +
    +
    + {{ $slot }} +
    +
    + + \ No newline at end of file From 9fb3438f918e106d5e11df700c681b64d4fb5995 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 18:41:01 +0800 Subject: [PATCH 040/298] this layout filtered by roles --- .../layouts/customer-layout.blade.php | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/resources/views/components/layouts/customer-layout.blade.php b/resources/views/components/layouts/customer-layout.blade.php index 780a46c..de2ebc5 100644 --- a/resources/views/components/layouts/customer-layout.blade.php +++ b/resources/views/components/layouts/customer-layout.blade.php @@ -1,18 +1,15 @@ -
    - -
    - Customer Site + Welcome @include('partials.head') - -
    \ No newline at end of file From c2d1d937674c344be4208d59c540a0fe1a0cf7e8 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 23:08:00 +0800 Subject: [PATCH 056/298] icon nadiswap --- public/nadiswap-icon.png | Bin 0 -> 316915 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/nadiswap-icon.png diff --git a/public/nadiswap-icon.png b/public/nadiswap-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..62a2b9fd8b4b15e1715eb4fa32b076d950ba5a5b GIT binary patch literal 316915 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

    <~1Vo}j#h~bZ36Q9vFDktkQcH%d(`&h%1&M@2 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 Date: Mon, 21 Apr 2025 23:08:17 +0800 Subject: [PATCH 057/298] table delivery address --- ...135019_create_delivery_addresses_table.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 database/migrations/2025_04_21_135019_create_delivery_addresses_table.php diff --git a/database/migrations/2025_04_21_135019_create_delivery_addresses_table.php b/database/migrations/2025_04_21_135019_create_delivery_addresses_table.php new file mode 100644 index 0000000..2dc71f7 --- /dev/null +++ b/database/migrations/2025_04_21_135019_create_delivery_addresses_table.php @@ -0,0 +1,36 @@ +id(); + $table->unsignedBigInteger('user_id'); // Foreign key for the user + $table->string('address_line_1'); + $table->string('address_line_2')->nullable(); + $table->string('city'); + $table->string('state'); + $table->string('postal_code'); + $table->string('country'); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); // Foreign key constraint + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('delivery_addresses'); + } +}; From f449489352aed3636b643a4a6760e2ce32a2c711 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 21 Apr 2025 23:08:42 +0800 Subject: [PATCH 058/298] tukar app icon --- .../layouts/customer-layout.blade.php | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/resources/views/components/layouts/customer-layout.blade.php b/resources/views/components/layouts/customer-layout.blade.php index de2ebc5..b70feac 100644 --- a/resources/views/components/layouts/customer-layout.blade.php +++ b/resources/views/components/layouts/customer-layout.blade.php @@ -16,13 +16,9 @@

    -
    + + \ No newline at end of file From df8397f8cdfd3ffa1c49028ce26ff0ce102cb252 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Fri, 25 Apr 2025 20:23:32 +0800 Subject: [PATCH 071/298] update user seeder --- database/seeders/UserSeeder.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php index 15e1bf8..e978a9f 100644 --- a/database/seeders/UserSeeder.php +++ b/database/seeders/UserSeeder.php @@ -19,7 +19,12 @@ public function run(): void // Create an admin user $admin = User::create([ 'name' => 'Admin User', + 'first_name' => 'Admin', + 'last_name' => 'User', + 'username' => 'adminuser', + 'gender'=>'male', 'email' => 'admin@demo.oo', + 'phone_number' => '1234567890', 'password' => bcrypt('password'), // Use a secure password ]); $admin->assignRole('admin'); @@ -27,8 +32,14 @@ public function run(): void // Create a seller user $seller = User::create([ 'name' => 'Seller User', + 'first_name' => 'Seller', + 'last_name' => 'User', + 'username' => 'selleruser', + 'gender'=>'male', 'email' => 'seller@demo.oo', 'password' => bcrypt('password'), // Use a secure password + 'phone_number' => '1234567890', + 'matrix_number' => 'M123', ]); $seller->assignRole('seller'); } From e826c50cd590d2eccd20d89681bf57d3eb94c02b Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Fri, 25 Apr 2025 20:25:29 +0800 Subject: [PATCH 072/298] test --- database/seeders/UserSeeder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php index e978a9f..a8ee251 100644 --- a/database/seeders/UserSeeder.php +++ b/database/seeders/UserSeeder.php @@ -24,7 +24,7 @@ public function run(): void 'username' => 'adminuser', 'gender'=>'male', 'email' => 'admin@demo.oo', - 'phone_number' => '1234567890', + 'phone_number' => '0167797762', 'password' => bcrypt('password'), // Use a secure password ]); $admin->assignRole('admin'); From a7f90ce4c56061868f7f83d508854c6d499370d0 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Fri, 25 Apr 2025 22:42:30 +0800 Subject: [PATCH 073/298] add clockwork --- .env.example | 65 ---------------------------- composer.json | 1 + composer.lock | 82 ++++++++++++++++++++++++++++++++++-- storage/clockwork/.gitignore | 3 ++ 4 files changed, 83 insertions(+), 68 deletions(-) delete mode 100644 .env.example create mode 100644 storage/clockwork/.gitignore diff --git a/.env.example b/.env.example deleted file mode 100644 index 35db1dd..0000000 --- a/.env.example +++ /dev/null @@ -1,65 +0,0 @@ -APP_NAME=Laravel -APP_ENV=local -APP_KEY= -APP_DEBUG=true -APP_URL=http://localhost - -APP_LOCALE=en -APP_FALLBACK_LOCALE=en -APP_FAKER_LOCALE=en_US - -APP_MAINTENANCE_DRIVER=file -# APP_MAINTENANCE_STORE=database - -PHP_CLI_SERVER_WORKERS=4 - -BCRYPT_ROUNDS=12 - -LOG_CHANNEL=stack -LOG_STACK=single -LOG_DEPRECATIONS_CHANNEL=null -LOG_LEVEL=debug - -DB_CONNECTION=sqlite -# DB_HOST=127.0.0.1 -# DB_PORT=3306 -# DB_DATABASE=laravel -# DB_USERNAME=root -# DB_PASSWORD= - -SESSION_DRIVER=database -SESSION_LIFETIME=120 -SESSION_ENCRYPT=false -SESSION_PATH=/ -SESSION_DOMAIN=null - -BROADCAST_CONNECTION=log -FILESYSTEM_DISK=local -QUEUE_CONNECTION=database - -CACHE_STORE=database -# CACHE_PREFIX= - -MEMCACHED_HOST=127.0.0.1 - -REDIS_CLIENT=phpredis -REDIS_HOST=127.0.0.1 -REDIS_PASSWORD=null -REDIS_PORT=6379 - -MAIL_MAILER=log -MAIL_SCHEME=null -MAIL_HOST=127.0.0.1 -MAIL_PORT=2525 -MAIL_USERNAME=null -MAIL_PASSWORD=null -MAIL_FROM_ADDRESS="hello@example.com" -MAIL_FROM_NAME="${APP_NAME}" - -AWS_ACCESS_KEY_ID= -AWS_SECRET_ACCESS_KEY= -AWS_DEFAULT_REGION=us-east-1 -AWS_BUCKET= -AWS_USE_PATH_STYLE_ENDPOINT=false - -VITE_APP_NAME="${APP_NAME}" diff --git a/composer.json b/composer.json index 2a7611d..cea9693 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "license": "MIT", "require": { "php": "^8.2", + "itsgoingd/clockwork": "^5.3", "laravel/framework": "^12.0", "laravel/tinker": "^2.10.1", "livewire/flux": "^2.0", diff --git a/composer.lock b/composer.lock index 4739bb4..31ddb0d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cfacc0239ed48259734c39b862d233f6", + "content-hash": "36bb79887abd378b45c65a92a14cd6b4", "packages": [ { "name": "brick/math", @@ -1054,6 +1054,82 @@ ], "time": "2025-02-03T10:55:03+00:00" }, + { + "name": "itsgoingd/clockwork", + "version": "v5.3.4", + "source": { + "type": "git", + "url": "https://github.com/itsgoingd/clockwork.git", + "reference": "c27ad77a08a9e58bf0049de46969fa4fe3b506e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/c27ad77a08a9e58bf0049de46969fa4fe3b506e5", + "reference": "c27ad77a08a9e58bf0049de46969fa4fe3b506e5", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.1" + }, + "suggest": { + "ext-pdo": "Needed in order to use a SQL database for metadata storage", + "ext-pdo_mysql": "Needed in order to use MySQL for metadata storage", + "ext-pdo_postgres": "Needed in order to use Postgres for metadata storage", + "ext-pdo_sqlite": "Needed in order to use a SQLite for metadata storage", + "ext-redis": "Needed in order to use Redis for metadata storage", + "php-http/discovery": "Vanilla integration - required for the middleware zero-configuration setup" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Clockwork": "Clockwork\\Support\\Laravel\\Facade" + }, + "providers": [ + "Clockwork\\Support\\Laravel\\ClockworkServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Clockwork\\": "Clockwork/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "itsgoingd", + "email": "itsgoingd@luzer.sk", + "homepage": "https://twitter.com/itsgoingd" + } + ], + "description": "php dev tools in your browser", + "homepage": "https://underground.works/clockwork", + "keywords": [ + "Devtools", + "debugging", + "laravel", + "logging", + "lumen", + "profiling", + "slim" + ], + "support": { + "issues": "https://github.com/itsgoingd/clockwork/issues", + "source": "https://github.com/itsgoingd/clockwork/tree/v5.3.4" + }, + "funding": [ + { + "url": "https://github.com/itsgoingd", + "type": "github" + } + ], + "time": "2025-02-09T15:57:21+00:00" + }, { "name": "laravel/framework", "version": "v12.2.0", @@ -8287,12 +8363,12 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.2" }, - "platform-dev": {}, + "platform-dev": [], "plugin-api-version": "2.6.0" } diff --git a/storage/clockwork/.gitignore b/storage/clockwork/.gitignore new file mode 100644 index 0000000..3fac1bf --- /dev/null +++ b/storage/clockwork/.gitignore @@ -0,0 +1,3 @@ +*.json +*.json.gz +index From d639991bb9568755139bfac0c075e18f17ddd270 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 26 Apr 2025 00:47:21 +0800 Subject: [PATCH 074/298] updated sidebar item --- resources/views/components/layouts/app/sidebar.blade.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index 9f1efe6..e83522a 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -38,6 +38,10 @@ class="fixed top-0 left-0 z-40 w-64 h-screen transition-transform -translate-x-f @hasrole('seller') + + + + @endhasrole From c4ce95b62c8a105b05e24b5f249b80a400ac5689 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 26 Apr 2025 01:05:39 +0800 Subject: [PATCH 075/298] add CategoryController, Category model, migration, and categories view --- .../Controllers/Seller/CategoryController.php | 66 +++++++++++++++++++ app/Models/Category.php | 10 +++ ...5_04_25_165908_create_categories_table.php | 27 ++++++++ resources/views/seller/categories.blade.php | 33 ++++++++++ 4 files changed, 136 insertions(+) create mode 100644 app/Http/Controllers/Seller/CategoryController.php create mode 100644 app/Models/Category.php create mode 100644 database/migrations/2025_04_25_165908_create_categories_table.php create mode 100644 resources/views/seller/categories.blade.php diff --git a/app/Http/Controllers/Seller/CategoryController.php b/app/Http/Controllers/Seller/CategoryController.php new file mode 100644 index 0000000..816d8cd --- /dev/null +++ b/app/Http/Controllers/Seller/CategoryController.php @@ -0,0 +1,66 @@ +id(); + $table->string('name')->unique(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('categories'); + } +}; diff --git a/resources/views/seller/categories.blade.php b/resources/views/seller/categories.blade.php new file mode 100644 index 0000000..3251747 --- /dev/null +++ b/resources/views/seller/categories.blade.php @@ -0,0 +1,33 @@ + + Categories + + @if (session('success')) + + @endif + + @if ($errors->any()) + + @endif + + +
    + +
    + + + + +
    \ No newline at end of file From c15147ce6f926a0791389f6f488dc41457867559 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Sat, 26 Apr 2025 01:05:48 +0800 Subject: [PATCH 076/298] add Categories route and sidebar item for sellers --- resources/views/components/layouts/app/sidebar.blade.php | 1 + resources/views/seller/products.blade.php | 3 ++- routes/web.php | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index e83522a..0875f81 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -38,6 +38,7 @@ class="fixed top-0 left-0 z-40 w-64 h-screen transition-transform -translate-x-f @hasrole('seller') + diff --git a/resources/views/seller/products.blade.php b/resources/views/seller/products.blade.php index 5dcb38f..479ddd2 100644 --- a/resources/views/seller/products.blade.php +++ b/resources/views/seller/products.blade.php @@ -1,6 +1,6 @@
    -

    My Products

    + My Products @if (session('success')) @endif +
    @@ -127,6 +81,21 @@ class="mx-auto grid max-w-screen-xl grid-cols-2 gap-8 text-gray-500 dark:text-gr

    Electronics

    + + + +
    + +
    + +
    {{-- fILTTERS --}}
    @@ -174,13 +143,21 @@ class="mx-auto grid max-w-screen-xl grid-cols-2 gap-8 text-gray-500 dark:text-gr
    + @if(isset($recommendedCategory) && $recommendedCategory) +
    +

    + Recommended for you: {{ $recommendedCategory }} +

    +
    + @endif
    + {{-- Products are already ordered: recommended category first --}} @foreach ($products as $product)
    @@ -188,7 +165,7 @@ class="mx-auto grid max-w-screen-xl grid-cols-2 gap-8 text-gray-500 dark:text-gr {{ $product->name }} - +

    {{$product->category}}

    @for ($i = 1; $i <= 5; $i++) @@ -464,7 +441,8 @@ class="inline-flex items-center rounded-lg bg-primary-700 px-5 py-2.5 text-sm fo
    - +
    @@ -655,7 +633,7 @@ class="inline-flex items-center rounded-lg bg-primary-700 px-5 py-2.5 text-sm fo Fourth star -
    -
    - -
    - -
    -
    - -
    - -
    -
    @@ -861,4 +782,5 @@ class="inline-flex items-center rounded-lg bg-primary-700 px-5 py-2.5 text-sm fo - \ No newline at end of file + +``` \ No newline at end of file From c72c84a2a5eb596179c5e8cb2cc5a27287ab7d76 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Sat, 26 Apr 2025 03:39:28 +0800 Subject: [PATCH 078/298] reccomendation algorithm --- app/Http/Controllers/BuyerController.php | 50 ++++++++++++++++++++---- app/Models/User.php | 5 +++ app/Models/UserCategoryPreference.php | 15 +++++++ routes/web.php | 2 + 4 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 app/Models/UserCategoryPreference.php diff --git a/app/Http/Controllers/BuyerController.php b/app/Http/Controllers/BuyerController.php index 5bde544..eb87111 100644 --- a/app/Http/Controllers/BuyerController.php +++ b/app/Http/Controllers/BuyerController.php @@ -32,14 +32,39 @@ public function index() }) ->get(); - // Increment weight for the first matching product's category - if ($user && $products->count() > 0 && $products[0]->category) { - $pref = \App\Models\UserCategoryPreference::firstOrCreate( - ['user_id' => $user->id, 'category' => $products[0]->category], - ['weight' => 0] - ); - $pref->increment('weight'); - $preferredCategories[$products[0]->category] = $pref->weight; + // Adjust weights based on search frequency + if ($user && $products->count() > 0) { + // Count categories in search results + $categoryCounts = []; + foreach ($products as $product) { + if ($product->category) { + $categoryCounts[$product->category] = ($categoryCounts[$product->category] ?? 0) + 1; + } + } + // Increase weight for categories found, decrease for others + foreach ($categoryCounts as $category => $count) { + $pref = \App\Models\UserCategoryPreference::firstOrCreate( + ['user_id' => $user->id, 'category' => $category], + ['weight' => 0] + ); + $pref->increment('weight', $count); // Increase by frequency in search results + $preferredCategories[$category] = $pref->weight; + } + // Decay weights for categories not found in this search (by 1 per search, not by count) + //TODO- decay weights slower + $allCategories = array_keys($preferredCategories); + foreach ($allCategories as $category) { + if (!isset($categoryCounts[$category])) { + $pref = \App\Models\UserCategoryPreference::where([ + 'user_id' => $user->id, + 'category' => $category + ])->first(); + if ($pref && $pref->weight > 0) { + $pref->decrement('weight', 1); // Only decrement by 1 per search + $preferredCategories[$category] = $pref->weight; + } + } + } } } else { $products = Product::all(); @@ -87,4 +112,13 @@ public function showAccount() // Logic to show the buyer's account details return view('buyer.account-profile', compact('user', 'ordersCount', 'reviewsCount', 'latestOrders','deliveryAddresses')); // Return the view for the buyer's account } + + public function resetRecommendations(Request $request) + { + $user = auth()->user(); + if ($user) { + $user->categoryPreferences()->delete(); + } + return redirect()->route('buyer.dashboard')->with('status', 'Recommendations reset.'); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 906f1fa..6ddf172 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -79,4 +79,9 @@ public function deliveryAddresses() { return $this->hasMany(DeliveryAddress::class); } + + public function categoryPreferences() + { + return $this->hasMany(\App\Models\UserCategoryPreference::class); + } } diff --git a/app/Models/UserCategoryPreference.php b/app/Models/UserCategoryPreference.php new file mode 100644 index 0000000..c92dc3d --- /dev/null +++ b/app/Models/UserCategoryPreference.php @@ -0,0 +1,15 @@ +belongsTo(User::class); + } +} diff --git a/routes/web.php b/routes/web.php index 1b7a060..406fc76 100644 --- a/routes/web.php +++ b/routes/web.php @@ -69,4 +69,6 @@ Route::delete('/reviews/{review}', [ReviewController::class, 'destroy'])->name('reviews.destroy'); }); +Route::post('/buyer/reset-recommendations', [BuyerController::class, 'resetRecommendations'])->name('buyer.reset_recommendations')->middleware('auth'); + require __DIR__.'/auth.php'; From 82aaff2b44c74ad6fcc37a87b1c1f02240797696 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Sat, 26 Apr 2025 03:40:57 +0800 Subject: [PATCH 079/298] recommendation algorithm --- resources/views/buyer/dashboard.blade.php | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/resources/views/buyer/dashboard.blade.php b/resources/views/buyer/dashboard.blade.php index 404eaad..5b436cb 100644 --- a/resources/views/buyer/dashboard.blade.php +++ b/resources/views/buyer/dashboard.blade.php @@ -1,5 +1,5 @@ -
    + {{--

    Search + @if(isset($recommendedCategory) && $recommendedCategory) +
    + @csrf + +
    + @endif

    {{-- fILTTERS --}}
    @@ -224,7 +236,7 @@ class="inline-flex items-center rounded-lg bg-primary-700 px-5 py-2.5 text-sm fo
    - + {{--
    - + --}}
    From 4c3e4734d0d729f825dbfb1b83ba058ebb38ea52 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Sat, 26 Apr 2025 03:41:18 +0800 Subject: [PATCH 080/298] product seeder --- app/Models/Product.php | 4 +- database/factories/ProductFactory.php | 76 +++++++++++++++++++++++++++ database/factories/UserFactory.php | 36 +++++++------ database/seeders/DatabaseSeeder.php | 1 + database/seeders/ProductSeeder.php | 25 +++++++++ 5 files changed, 125 insertions(+), 17 deletions(-) create mode 100644 database/factories/ProductFactory.php create mode 100644 database/seeders/ProductSeeder.php diff --git a/app/Models/Product.php b/app/Models/Product.php index 71ff7a0..30e5d48 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -3,10 +3,12 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Factories\HasFactory; class Product extends Model { - // + use HasFactory; + protected $fillable = [ 'name', 'description', diff --git a/database/factories/ProductFactory.php b/database/factories/ProductFactory.php new file mode 100644 index 0000000..b09bbe1 --- /dev/null +++ b/database/factories/ProductFactory.php @@ -0,0 +1,76 @@ + + */ + public function definition(): array + { + $categories = ['Electronics', 'Clothing', 'Home & Garden', 'Books', 'Toys', 'Sports', 'Beauty', 'Food']; + + // Try to get a random user ID from the users table + $userId = \App\Models\User::inRandomOrder()->value('id'); + + // If no users exist, create one using the factory + if (!$userId) { + $userId = \App\Models\User::factory()->create()->id; + } + + return [ + 'name' => $this->faker->unique()->words(rand(1, 3), true), + 'description' => $this->faker->paragraphs(rand(1, 3), true), + 'category' => Arr::random($categories), + 'price' => $this->faker->randomFloat(2, 1, 1000), + 'stock' => $this->faker->numberBetween(0, 500), + 'image' => 'storage/random' . rand(1, 6) . '.webp', + 'seller_id' => $userId, + 'created_at' => $this->faker->dateTimeBetween('-1 year', 'now'), + 'updated_at' => $this->faker->dateTimeBetween('-1 year', 'now'), + ]; + } + + /** + * Indicate that the product is out of stock + */ + public function outOfStock(): static + { + return $this->state(function (array $attributes) { + return [ + 'stock' => 0, + ]; + }); + } + + /** + * Indicate that the product has a specific category + */ + public function inCategory(string $category): static + { + return $this->state(function (array $attributes) use ($category) { + return [ + 'category' => $category, + ]; + }); + } + + /** + * Indicate that the product has a discount price + */ + public function discounted(float $percentage): static + { + return $this->state(function (array $attributes) use ($percentage) { + $discount = $attributes['price'] * ($percentage / 100); + return [ + 'price' => $attributes['price'] - $discount, + ]; + }); + } +} \ No newline at end of file diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 584104c..63699e8 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -2,43 +2,47 @@ namespace Database\Factories; +use App\Models\User; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Str; -/** - * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User> - */ class UserFactory extends Factory { - /** - * The current password being used by the factory. - */ protected static ?string $password; - /** - * Define the model's default state. - * - * @return array - */ public function definition(): array { + $gender = $this->faker->randomElement(['male', 'female']); + $firstName = $this->faker->firstName($gender); + $lastName = $this->faker->lastName(); + return [ - 'name' => fake()->name(), - 'email' => fake()->unique()->safeEmail(), + 'first_name' => $firstName, + 'last_name' => $lastName, + 'username' => $this->faker->unique()->userName(), + 'gender' => $gender, + 'name' => "$firstName $lastName", // Full name + 'email' => $this->faker->unique()->safeEmail(), 'email_verified_at' => now(), 'password' => static::$password ??= Hash::make('password'), + 'phone_number' => $this->faker->phoneNumber(), + 'matrix_number' => 'M' . $this->faker->unique()->numberBetween(1000, 9999), 'remember_token' => Str::random(10), ]; } - /** - * Indicate that the model's email address should be unverified. - */ public function unverified(): static { return $this->state(fn (array $attributes) => [ 'email_verified_at' => null, ]); } + + public function seller(): static + { + return $this->afterCreating(function (User $user) { + $user->assignRole('seller'); + }); + } } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 405c606..da6cf25 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -15,6 +15,7 @@ public function run(): void $this->call([ RoleSeeder::class, UserSeeder::class, + ProductSeeder::class, ]); } } diff --git a/database/seeders/ProductSeeder.php b/database/seeders/ProductSeeder.php new file mode 100644 index 0000000..4e34099 --- /dev/null +++ b/database/seeders/ProductSeeder.php @@ -0,0 +1,25 @@ +create(); + + // You can also create specific products, such as out-of-stock or discounted products + Product::factory()->outOfStock()->create(); + Product::factory()->discounted(20)->create(); // 20% discount + } +} From c840b0316c968527d905908f5b595445551a35a2 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Sat, 26 Apr 2025 03:41:39 +0800 Subject: [PATCH 081/298] buyer user seeder --- database/seeders/UserSeeder.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php index a8ee251..fa0e96c 100644 --- a/database/seeders/UserSeeder.php +++ b/database/seeders/UserSeeder.php @@ -42,5 +42,19 @@ public function run(): void 'matrix_number' => 'M123', ]); $seller->assignRole('seller'); + + // Create a buyer user + $seller = User::create([ + 'name' => 'Buyer User', + 'first_name' => 'Buyer', + 'last_name' => 'User', + 'username' => 'buyeruser', + 'gender'=>'male', + 'email' => 'buyer@demo.oo', + 'password' => bcrypt('password'), // Use a secure password + 'phone_number' => '1234567890', + 'matrix_number' => 'B123', + ]); + $seller->assignRole('buyer'); } } From 46fd0bcc1609adf3f951e83befc0e95ae760faaa Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 28 Apr 2025 00:24:52 +0800 Subject: [PATCH 082/298] create categories and display pn category page --- .../Controllers/Seller/CategoryController.php | 14 ++++++- app/Models/Category.php | 8 ++-- ...5_04_25_165908_create_categories_table.php | 1 + resources/views/Modal/add-category.blade.php | 41 +++++++++++++++++++ resources/views/seller/categories.blade.php | 21 +++++++++- routes/web.php | 1 + 6 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 resources/views/Modal/add-category.blade.php diff --git a/app/Http/Controllers/Seller/CategoryController.php b/app/Http/Controllers/Seller/CategoryController.php index 816d8cd..ede40b4 100644 --- a/app/Http/Controllers/Seller/CategoryController.php +++ b/app/Http/Controllers/Seller/CategoryController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Seller; use App\Http\Controllers\Controller; +use App\Models\Category; use Illuminate\Http\Request; class CategoryController extends Controller @@ -13,7 +14,8 @@ class CategoryController extends Controller public function index() { // - return view('seller.categories'); + $categories = Category::all(); + return view('seller.categories', compact('categories')); } /** @@ -29,7 +31,15 @@ public function create() */ public function store(Request $request) { - // + $request->validate([ + 'name' => 'required|string|max:255|unique:categories,name', + ]); + + Category::create([ + 'name' => $request->name, + ]); + + return redirect()->back()->with('success', 'Category created successfully.'); } /** diff --git a/app/Models/Category.php b/app/Models/Category.php index 6a8a406..4dcca22 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -1,10 +1,12 @@ id(); $table->string('name')->unique(); + $table->timestamps(); }); } diff --git a/resources/views/Modal/add-category.blade.php b/resources/views/Modal/add-category.blade.php new file mode 100644 index 0000000..0814cf9 --- /dev/null +++ b/resources/views/Modal/add-category.blade.php @@ -0,0 +1,41 @@ + + \ No newline at end of file diff --git a/resources/views/seller/categories.blade.php b/resources/views/seller/categories.blade.php index 3251747..b32fecc 100644 --- a/resources/views/seller/categories.blade.php +++ b/resources/views/seller/categories.blade.php @@ -27,7 +27,26 @@ class="block text-white bg-pink-700 hover:bg-pink-800 focus:ring-4 focus:outline - +
    + + + + + + + + @foreach ($categories as $category) + + + + @endforeach + +
    Category Name
    + {{ $category->name }} +
    +
    + + @include('Modal.add-category') \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 8666fcd..26844d5 100644 --- a/routes/web.php +++ b/routes/web.php @@ -45,6 +45,7 @@ Route::resource('products', ProductController::class)->except(['show']); Route::get('/categories', [CategoryController::class, 'index'])->name('categories'); + Route::post('/categories/store', [CategoryController::class, 'store'])->name('categories.store'); }); Route::middleware(['auth'])->prefix('profile')->name('profile.')->group(function () { From 2a6e81caa126a68866038f17d457333a25239aea Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 28 Apr 2025 00:34:50 +0800 Subject: [PATCH 083/298] time add review, nanti categorynya bboleh diselect by apa yang dia add --- app/Http/Controllers/Seller/ProductController.php | 4 +++- resources/views/seller/products.blade.php | 14 +++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/Seller/ProductController.php b/app/Http/Controllers/Seller/ProductController.php index 070b851..7ef5087 100644 --- a/app/Http/Controllers/Seller/ProductController.php +++ b/app/Http/Controllers/Seller/ProductController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Seller; use App\Http\Controllers\Controller; +use App\Models\Category; use App\Models\Product; use Illuminate\Http\Request; @@ -14,8 +15,9 @@ class ProductController extends Controller public function index() { $products = Product::all(); + $categories = Category::all(); // $avgRating = $product->reviews()->avg('rating') ?? 0 ; - return view('seller.products', compact('products')); + return view('seller.products', compact('products','categories')); } /** diff --git a/resources/views/seller/products.blade.php b/resources/views/seller/products.blade.php index 479ddd2..147e04b 100644 --- a/resources/views/seller/products.blade.php +++ b/resources/views/seller/products.blade.php @@ -39,6 +39,7 @@ class="block text-white bg-pink-700 hover:bg-pink-800 focus:ring-4 focus:outline Stock Rating Total Reviews + Category @@ -73,6 +74,9 @@ class="w-16 h-16 object-cover rounded"> {{ $product->reviews->count() }} + + {{ $product->category }} + + + + + + + + + + + + + @endforeach @include('Modal.add-category') - - \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 26844d5..c944d16 100644 --- a/routes/web.php +++ b/routes/web.php @@ -44,8 +44,7 @@ Route::get('/dashboard', [SellerController::class, 'index'])->name('dashboard'); Route::resource('products', ProductController::class)->except(['show']); - Route::get('/categories', [CategoryController::class, 'index'])->name('categories'); - Route::post('/categories/store', [CategoryController::class, 'store'])->name('categories.store'); + Route::resource('categories', CategoryController::class)->except(['show']); }); Route::middleware(['auth'])->prefix('profile')->name('profile.')->group(function () { From 1a974bd497e6fd25a424028b7ea041fe0810d340 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Mon, 28 Apr 2025 15:49:59 +0800 Subject: [PATCH 085/298] Enhance product management interface with export functionality and improved table layout --- .../views/components/layouts/app.blade.php | 198 +++++++- resources/views/seller/products.blade.php | 433 ++++++++++-------- 2 files changed, 444 insertions(+), 187 deletions(-) diff --git a/resources/views/components/layouts/app.blade.php b/resources/views/components/layouts/app.blade.php index ad1a014..50fa92f 100644 --- a/resources/views/components/layouts/app.blade.php +++ b/resources/views/components/layouts/app.blade.php @@ -7,11 +7,201 @@ + \ No newline at end of file diff --git a/resources/views/seller/products.blade.php b/resources/views/seller/products.blade.php index 147e04b..6ec88e0 100644 --- a/resources/views/seller/products.blade.php +++ b/resources/views/seller/products.blade.php @@ -17,189 +17,235 @@ @endif - +
    - +
    + +{{-- + + + + + + + + + + + + + + + + @foreach ($products as $product) + + + + + + + + + + + + + @endforeach + + +
    + + Image + + + + + Product Name + + + + + + Category + + + + + + Price + - -
    - - - - - - - - - - - - - - - - - - @foreach ($products as $product) - - + + + + + + + + + + @foreach ($products as $product) + + - - - - - - - - - - - + + + + + + + + + + + + @endforeach + + +
    ImageProduct NameDescriptionPriceStockRatingTotal ReviewsCategory
    - @if ($product->image) + + + + + Description + + + + + + Rating + + + + + Total Reviews + + + + + + + + + + + + + + +
    + @if ($product->image) {{ $product->name }} @else No Image @endif - - {{ $product->name }} - - {{ $product->description }} - - ${{ $product->price }} - - {{ $product->stock }} - - {{ $product->reviews->avg('rating') ? $product->reviews->avg('rating') : 'No reviews yet' }} - - {{ $product->reviews->count() }} - - {{ $product->category }} - - - - - -
    - @csrf - @method('DELETE') - -
    -
    - - - View Product - -
    {{ $product->name }} {{ $product->category }} RM{{ $product->price }} {{ $product->description }} {{ $product->reviews->avg('rating') ? $product->reviews->avg('rating') : 'No reviews yet' }} {{ $product->reviews->count() }} + +
    + @csrf + @method('DELETE') + +
    + + + View Product + +
    --}} - -
    + + Rating + + + + + Total Reviews + + + + + {{-- --}} + + + + {{-- --}} + + + + {{-- --}} + +
    + @if ($product->image) + {{ $product->name }} + @else + No Image + @endif + {{ $product->name }} {{ $product->category }} RM{{ $product->price }} {{ $product->description }} {{ $product->reviews->avg('rating') ? $product->reviews->avg('rating') : 'No reviews yet' }} {{ $product->reviews->count() }} + +
    + @csrf + @method('DELETE') + +
    + + + View Product + +
    + + - +
    - +
    - +
    - + - - + +
    + + +
    +
    + @csrf +
    + + +
    +
    +
    + RM +
    + +
    + +
    +
    + + + \ No newline at end of file diff --git a/resources/views/Modal/edit-product.blade.php b/resources/views/Modal/edit-product.blade.php new file mode 100644 index 0000000..bdeef52 --- /dev/null +++ b/resources/views/Modal/edit-product.blade.php @@ -0,0 +1,68 @@ + + \ No newline at end of file diff --git a/resources/views/Modal/edit-shipping.blade.php b/resources/views/Modal/edit-shipping.blade.php new file mode 100644 index 0000000..1e6d71c --- /dev/null +++ b/resources/views/Modal/edit-shipping.blade.php @@ -0,0 +1,60 @@ + + \ No newline at end of file diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index 8fca453..e247af8 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -39,7 +39,7 @@ class="fixed top-0 left-0 z-40 w-64 h-screen transition-transform -translate-x-f - + diff --git a/resources/views/seller/products.blade.php b/resources/views/seller/products.blade.php index c35eab5..4c40bad 100644 --- a/resources/views/seller/products.blade.php +++ b/resources/views/seller/products.blade.php @@ -222,74 +222,7 @@ class="w-16 h-16 object-cover rounded"> Edit @push('modal') - - + @include('Modal.edit-product') @endpush diff --git a/resources/views/seller/shipping.blade.php b/resources/views/seller/shipping.blade.php new file mode 100644 index 0000000..0092606 --- /dev/null +++ b/resources/views/seller/shipping.blade.php @@ -0,0 +1,78 @@ + + Shippings + @if (session('success')) + + @endif + + @if ($errors->any()) + + @endif + + +
    + +
    + +
    + + + + + + + + + + + + @foreach ($shippings as $shipping) + + + + + @push('modal') + @include('Modal.edit-shipping') + @endpush + + + + @endforeach + +
    + + Location Name + + + + Price + + + + + + + +
    {{ $shipping->place }}RM{{ $shipping->shipping_fee }} + + + +
    +
    + + @include('Modal.add-shipping') +
    \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index c944d16..a05ff82 100644 --- a/routes/web.php +++ b/routes/web.php @@ -9,6 +9,7 @@ use App\Http\Controllers\DeliveryAddressController; use App\Http\Controllers\ProfileController; use App\Http\Controllers\Seller\CategoryController; +use App\Http\Controllers\Seller\ShippingController; use App\Livewire\Settings\Appearance; use App\Livewire\Settings\Password; use App\Livewire\Settings\Profile; @@ -45,6 +46,7 @@ Route::resource('products', ProductController::class)->except(['show']); Route::resource('categories', CategoryController::class)->except(['show']); + Route::resource('shippings', ShippingController::class); }); Route::middleware(['auth'])->prefix('profile')->name('profile.')->group(function () { From 9dd2f60feafc3936672125836a53be16a306c88b Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Tue, 29 Apr 2025 01:05:31 +0800 Subject: [PATCH 088/298] CRUD for Shipping fee --- resources/views/Modal/add-shipping.blade.php | 2 +- resources/views/seller/shipping.blade.php | 11 ++++++++--- routes/web.php | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/resources/views/Modal/add-shipping.blade.php b/resources/views/Modal/add-shipping.blade.php index 43655cb..8d75733 100644 --- a/resources/views/Modal/add-shipping.blade.php +++ b/resources/views/Modal/add-shipping.blade.php @@ -35,7 +35,7 @@ class="block w-full p-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border bor
    RM
    - + + +
    + @csrf + @method('DELETE') + +
    diff --git a/routes/web.php b/routes/web.php index a05ff82..e7890ae 100644 --- a/routes/web.php +++ b/routes/web.php @@ -46,7 +46,7 @@ Route::resource('products', ProductController::class)->except(['show']); Route::resource('categories', CategoryController::class)->except(['show']); - Route::resource('shippings', ShippingController::class); + Route::resource('shippings', ShippingController::class)->except(['show']); }); Route::middleware(['auth'])->prefix('profile')->name('profile.')->group(function () { From e57e86ec5c67626c6935ba62a7ae2eaf40a8787f Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Tue, 29 Apr 2025 20:43:06 +0800 Subject: [PATCH 089/298] Implement Order management features with CRUD operations and enhance order table with export functionality --- .../Controllers/Seller/OrderController.php | 70 +++++++ .../2025_04_19_153612_create_orders_table.php | 4 +- public/js/order-table.js | 177 ++++++++++++++++++ resources/views/seller/orders.blade.php | 118 ++++++++++++ 4 files changed, 368 insertions(+), 1 deletion(-) create mode 100644 app/Http/Controllers/Seller/OrderController.php create mode 100644 public/js/order-table.js create mode 100644 resources/views/seller/orders.blade.php diff --git a/app/Http/Controllers/Seller/OrderController.php b/app/Http/Controllers/Seller/OrderController.php new file mode 100644 index 0000000..2c8e306 --- /dev/null +++ b/app/Http/Controllers/Seller/OrderController.php @@ -0,0 +1,70 @@ +user()->id)->get(); + + return view('seller.orders',compact('orders')); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + // + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + // + } + + /** + * Display the specified resource. + */ + public function show(string $id) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(string $id) + { + // + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, string $id) + { + // + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(string $id) + { + // + } +} diff --git a/database/migrations/2025_04_19_153612_create_orders_table.php b/database/migrations/2025_04_19_153612_create_orders_table.php index 8fe2d2e..ae12947 100644 --- a/database/migrations/2025_04_19_153612_create_orders_table.php +++ b/database/migrations/2025_04_19_153612_create_orders_table.php @@ -17,7 +17,9 @@ public function up(): void $table->foreignId('seller_id')->constrained('users')->onDelete('cascade'); $table->json('items'); // Store cart items as JSON $table->decimal('total', 10, 2); - $table->string('status')->default('Pending'); // e.g., Pending, Completed + $table->string('delivery_status')->default('Pending'); // e.g., Pending, Completed + $table->string('payment_status')->default('Pending'); // e.g., Pending, Completed + $table->string('payment_method'); // e.g., Pending, Completed $table->timestamps(); }); } diff --git a/public/js/order-table.js b/public/js/order-table.js new file mode 100644 index 0000000..2e371d9 --- /dev/null +++ b/public/js/order-table.js @@ -0,0 +1,177 @@ +if (document.getElementById("order-table") && typeof simpleDatatables.DataTable !== 'undefined') { + let multiSelect = true; + +const exportCustomCSV = function(dataTable, userOptions = {}) { + + // A modified CSV export that includes a row of minuses at the start and end. + const clonedUserOptions = { + ...userOptions + } + clonedUserOptions.download = false + const csv = simpleDatatables.exportCSV(dataTable, clonedUserOptions) + // If CSV didn't work, exit. + if (!csv) { + return false + } + const defaults = { + download: true, + lineDelimiter: "\n", + columnDelimiter: ";" + } + const options = { + ...defaults, + ...clonedUserOptions, + rowRender: (row, tr, _index) => { + if (!tr.attributes) { + tr.attributes = {}; + } + if (!tr.attributes.class) { + tr.attributes.class = ""; + } + if (row.selected) { + tr.attributes.class += " selected"; + } else { + tr.attributes.class = tr.attributes.class.replace(" selected", ""); + } + return tr; + } + } + const separatorRow = Array(dataTable.data.headings.filter((_heading, index) => !dataTable.columns.settings[index]?.hidden).length) + .fill("+") + .join("+"); // Use "+" as the delimiter + + const str = separatorRow + options.lineDelimiter + csv + options.lineDelimiter + separatorRow; + + if (userOptions.download) { + // Create a link to trigger the download + const link = document.createElement("a"); + link.href = encodeURI("data:text/csv;charset=utf-8," + str); + link.download = (options.filename || "datatable_export") + ".txt"; + // Append the link + document.body.appendChild(link); + // Trigger the download + link.click(); + // Remove the link + document.body.removeChild(link); + } + + return str +} +const table = new simpleDatatables.DataTable("#order-table", { + + // caption: "Flowbite is an open-source library", + labels: { + // add custom text for the labels, full list: https://fiduswriter.github.io/simple-datatables/documentation/labels + placeholder: "Search...", + searchTitle: "Search within table", + pageTitle: "Page {page}", + perPage: "entries per page", + noRows: "No entries found", + info: "Showing {start} to {end} of {rows} entries", + noResults: "No results match your search query", + }, + header: true, // enable or disable the header + template: (options, dom) => "
    " + + "
    " + + // (options.paging && options.perPageSelect ? + // "
    " + + // "" + + // "
    " : "" + // ) + + ` + + + + + + +
    ` + + + (options.searchable ? + `
    ` + + "" + + "
    " : "" + ) + + "
    " + + "
    " + + "
    " + + (options.paging ? + "
    " : "" + ) + + "" + + "
    " +}) +const $exportButton = document.getElementById("exportDropdownButton"); +const $exportDropdownEl = document.getElementById("exportDropdown"); +const dropdown = new Dropdown($exportDropdownEl, $exportButton); +console.log(dropdown) + +document.getElementById("export-csv").addEventListener("click", () => { + simpleDatatables.exportCSV(table, { + download: true, + lineDelimiter: "\n", + columnDelimiter: ";" + }) +}) +let selectedRows = []; // Array to store selected rows + +table.on("datatable.selectrow", (rowIndex, event) => { + event.preventDefault(); + const row = table.data.data[rowIndex]; + const productId = row.attributes['data-id']; + console.log("row", row); + if (row.selected) { + row.attributes['class'] = '' + + row.selected = false; + selectedRows = selectedRows.filter(id => id !== productId); + } else { + row.attributes['class'] = '' + row.attributes['class'] = 'selected' + + row.selected = true; + selectedRows.push(productId); + console.log("push:", productId); + } + table.update(); + + // Enable or disable the Delete Selection button + document.getElementById("deleteSelectionButton").disabled = selectedRows.length === 0; + + console.log("Selected product id:", selectedRows); + + }); + // Handle Delete Selection Button + document.getElementById("deleteSelectionButton").addEventListener("click", () => { + if (selectedRows.length > 0) { + if (confirm("Are you sure you want to delete the selected rows?")) { + console.log("Deleting rows:", selectedRows.map( + id=>id + )); + // Perform your delete logic here (e.g., send an AJAX request) + } + } else { + alert("No rows selected."); + } + }); +}; \ No newline at end of file diff --git a/resources/views/seller/orders.blade.php b/resources/views/seller/orders.blade.php new file mode 100644 index 0000000..536cbba --- /dev/null +++ b/resources/views/seller/orders.blade.php @@ -0,0 +1,118 @@ + + Orders + + @if (session('success')) + + @endif + + @if ($errors->any()) + + @endif + {{-- js/order-table.js --}} + + + + + + + + + + + + + + + @foreach ($orders as $order) + + + + + + + + + + + @endforeach + +
    + + # + + + + Order ID + + + + + Buyer ID + + + + + Date Ordered + + + + + Price + + + + + Payment Method + + + + + Payment Status + + + + + Delivery Status + + +
    {{ $loop->iteration }} + {{ $order->id }} + @push('modal') + + @endpush + {{ $order->buyer->id }}{{ $order->created_at->format('Y-m-d') }}RM{{ number_format($order->total, 2) }}{{ $order->payment_method }}{{ $order->payment_status }}{{ $order->delivery_status }}
    + + @push('js') + + @endpush + + \ No newline at end of file From ea83d6d1ab8a7b9fb2f4a6a6a014f455f8cf53d5 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Tue, 29 Apr 2025 20:43:16 +0800 Subject: [PATCH 090/298] Refactor product listing to show only seller's products and implement CSV export functionality for the product table --- .../Controllers/Seller/ProductController.php | 2 +- public/js/product-table.js | 181 +++++++++++++++++ .../views/components/layouts/app.blade.php | 190 +----------------- .../components/layouts/app/sidebar.blade.php | 2 +- resources/views/seller/products.blade.php | 9 +- 5 files changed, 190 insertions(+), 194 deletions(-) create mode 100644 public/js/product-table.js diff --git a/app/Http/Controllers/Seller/ProductController.php b/app/Http/Controllers/Seller/ProductController.php index e170c55..c7b2dbb 100644 --- a/app/Http/Controllers/Seller/ProductController.php +++ b/app/Http/Controllers/Seller/ProductController.php @@ -14,7 +14,7 @@ class ProductController extends Controller */ public function index() { - $products = Product::all(); + $products = Product::where('seller_id', auth()->id())->get(); $categories = Category::all(); // $avgRating = $product->reviews()->avg('rating') ?? 0 ; return view('seller.products', compact('products','categories')); diff --git a/public/js/product-table.js b/public/js/product-table.js new file mode 100644 index 0000000..12c7fb4 --- /dev/null +++ b/public/js/product-table.js @@ -0,0 +1,181 @@ +if (document.getElementById("product-table") && typeof simpleDatatables.DataTable !== 'undefined') { + let multiSelect = true; + +const exportCustomCSV = function(dataTable, userOptions = {}) { + + // A modified CSV export that includes a row of minuses at the start and end. + const clonedUserOptions = { + ...userOptions + } + clonedUserOptions.download = false + const csv = simpleDatatables.exportCSV(dataTable, clonedUserOptions) + // If CSV didn't work, exit. + if (!csv) { + return false + } + const defaults = { + download: true, + lineDelimiter: "\n", + columnDelimiter: ";" + } + const options = { + ...defaults, + ...clonedUserOptions, + rowRender: (row, tr, _index) => { + if (!tr.attributes) { + tr.attributes = {}; + } + if (!tr.attributes.class) { + tr.attributes.class = ""; + } + if (row.selected) { + tr.attributes.class += " selected"; + } else { + tr.attributes.class = tr.attributes.class.replace(" selected", ""); + } + return tr; + } + } + const separatorRow = Array(dataTable.data.headings.filter((_heading, index) => !dataTable.columns.settings[index]?.hidden).length) + .fill("+") + .join("+"); // Use "+" as the delimiter + + const str = separatorRow + options.lineDelimiter + csv + options.lineDelimiter + separatorRow; + + if (userOptions.download) { + // Create a link to trigger the download + const link = document.createElement("a"); + link.href = encodeURI("data:text/csv;charset=utf-8," + str); + link.download = (options.filename || "datatable_export") + ".txt"; + // Append the link + document.body.appendChild(link); + // Trigger the download + link.click(); + // Remove the link + document.body.removeChild(link); + } + + return str +} +const table = new simpleDatatables.DataTable("#product-table", { + + // caption: "Flowbite is an open-source library", + labels: { + // add custom text for the labels, full list: https://fiduswriter.github.io/simple-datatables/documentation/labels + placeholder: "Search...", + searchTitle: "Search within table", + pageTitle: "Page {page}", + perPage: "entries per page", + noRows: "No entries found", + info: "Showing {start} to {end} of {rows} entries", + noResults: "No results match your search query", + }, + header: true, // enable or disable the header + template: (options, dom) => "
    " + + "
    " + + // (options.paging && options.perPageSelect ? + // "
    " + + // "" + + // "
    " : "" + // ) + + ` + + + + + + +
    ` + + + (options.searchable ? + `
    ` + + "" + + "
    " : "" + ) + + "
    " + + "
    " + + "
    " + + (options.paging ? + "
    " : "" + ) + + "" + + "
    " +}) +const $exportButton = document.getElementById("exportDropdownButton"); +const $exportDropdownEl = document.getElementById("exportDropdown"); +const dropdown = new Dropdown($exportDropdownEl, $exportButton); +console.log(dropdown) + +document.getElementById("export-csv").addEventListener("click", () => { + simpleDatatables.exportCSV(table, { + download: true, + lineDelimiter: "\n", + columnDelimiter: ";" + }) +}) +let selectedRows = []; // Array to store selected rows + +table.on("datatable.selectrow", (rowIndex, event) => { + event.preventDefault(); + const row = table.data.data[rowIndex]; + const productId = row.attributes['data-id']; + console.log("row", row); + if (row.selected) { + row.attributes['class'] = '' + + row.selected = false; + selectedRows = selectedRows.filter(id => id !== productId); + } else { + row.attributes['class'] = '' + row.attributes['class'] = 'selected' + + row.selected = true; + selectedRows.push(productId); + console.log("push:", productId); + } + table.update(); + + // Enable or disable the Delete Selection button + document.getElementById("deleteSelectionButton").disabled = selectedRows.length === 0; + + console.log("Selected product id:", selectedRows); + + }); + // Handle Delete Selection Button + document.getElementById("deleteSelectionButton").addEventListener("click", () => { + if (selectedRows.length > 0) { + if (confirm("Are you sure you want to delete the selected rows?")) { + console.log("Deleting rows:", selectedRows.map( + id=>id + )); + // Perform your delete logic here (e.g., send an AJAX request) + } + } else { + alert("No rows selected."); + } + }); +}; \ No newline at end of file diff --git a/resources/views/components/layouts/app.blade.php b/resources/views/components/layouts/app.blade.php index 59f580a..8e53178 100644 --- a/resources/views/components/layouts/app.blade.php +++ b/resources/views/components/layouts/app.blade.php @@ -13,195 +13,9 @@ sortable: false }); } - - - - - -if (document.getElementById("export-table") && typeof simpleDatatables.DataTable !== 'undefined') { - let multiSelect = true; - -const exportCustomCSV = function(dataTable, userOptions = {}) { - - // A modified CSV export that includes a row of minuses at the start and end. - const clonedUserOptions = { - ...userOptions - } - clonedUserOptions.download = false - const csv = simpleDatatables.exportCSV(dataTable, clonedUserOptions) - // If CSV didn't work, exit. - if (!csv) { - return false - } - const defaults = { - download: true, - lineDelimiter: "\n", - columnDelimiter: ";" - } - const options = { - ...defaults, - ...clonedUserOptions, - rowRender: (row, tr, _index) => { - if (!tr.attributes) { - tr.attributes = {}; - } - if (!tr.attributes.class) { - tr.attributes.class = ""; - } - if (row.selected) { - tr.attributes.class += " selected"; - } else { - tr.attributes.class = tr.attributes.class.replace(" selected", ""); - } - return tr; - } - } - const separatorRow = Array(dataTable.data.headings.filter((_heading, index) => !dataTable.columns.settings[index]?.hidden).length) - .fill("+") - .join("+"); // Use "+" as the delimiter - - const str = separatorRow + options.lineDelimiter + csv + options.lineDelimiter + separatorRow; - - if (userOptions.download) { - // Create a link to trigger the download - const link = document.createElement("a"); - link.href = encodeURI("data:text/csv;charset=utf-8," + str); - link.download = (options.filename || "datatable_export") + ".txt"; - // Append the link - document.body.appendChild(link); - // Trigger the download - link.click(); - // Remove the link - document.body.removeChild(link); - } - - return str -} -const table = new simpleDatatables.DataTable("#export-table", { - - // caption: "Flowbite is an open-source library", - labels: { - // add custom text for the labels, full list: https://fiduswriter.github.io/simple-datatables/documentation/labels - placeholder: "Search...", - searchTitle: "Search within table", - pageTitle: "Page {page}", - perPage: "entries per page", - noRows: "No entries found", - info: "Showing {start} to {end} of {rows} entries", - noResults: "No results match your search query", - }, - header: true, // enable or disable the header - template: (options, dom) => "
    " + - "
    " + - // (options.paging && options.perPageSelect ? - // "
    " + - // "" + - // "
    " : "" - // ) + - ` - - - - - - -
    ` - + - (options.searchable ? - `
    ` + - "" + - "
    " : "" - ) + - "
    " + - "
    " + - "
    " + - (options.paging ? - "
    " : "" - ) + - "" + - "
    " -}) -const $exportButton = document.getElementById("exportDropdownButton"); -const $exportDropdownEl = document.getElementById("exportDropdown"); -const dropdown = new Dropdown($exportDropdownEl, $exportButton); -console.log(dropdown) - -document.getElementById("export-csv").addEventListener("click", () => { - simpleDatatables.exportCSV(table, { - download: true, - lineDelimiter: "\n", - columnDelimiter: ";" - }) -}) -let selectedRows = []; // Array to store selected rows - -table.on("datatable.selectrow", (rowIndex, event) => { - event.preventDefault(); - const row = table.data.data[rowIndex]; - const productId = row.attributes['data-id']; - console.log("row", row); - if (row.selected) { - row.attributes['class'] = '' - - row.selected = false; - selectedRows = selectedRows.filter(id => id !== productId); - } else { - row.attributes['class'] = '' - row.attributes['class'] = 'selected' - - row.selected = true; - selectedRows.push(productId); - console.log("push:", productId); - } - table.update(); - - // Enable or disable the Delete Selection button - document.getElementById("deleteSelectionButton").disabled = selectedRows.length === 0; - - console.log("Selected product id:", selectedRows); - - }); - // Handle Delete Selection Button - document.getElementById("deleteSelectionButton").addEventListener("click", () => { - if (selectedRows.length > 0) { - if (confirm("Are you sure you want to delete the selected rows?")) { - console.log("Deleting rows:", selectedRows.map( - id=>id - )); - // Perform your delete logic here (e.g., send an AJAX request) - } - } else { - alert("No rows selected."); - } - }); -}; - - + @stack('js') + diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index e247af8..84afda4 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -40,7 +40,7 @@ class="fixed top-0 left-0 z-40 w-64 h-screen transition-transform -translate-x-f - + @endhasrole diff --git a/resources/views/seller/products.blade.php b/resources/views/seller/products.blade.php index 4c40bad..e7391cd 100644 --- a/resources/views/seller/products.blade.php +++ b/resources/views/seller/products.blade.php @@ -18,10 +18,7 @@ @endif - -
    -
    {{-- @@ -139,7 +136,7 @@ class="btn text-pink-500 hover:text-pink-700">
    --}} - +
    @@ -350,5 +347,9 @@ class="w-full text-white bg-pink-700 hover:bg-pink-800 focus:ring-4 focus:outlin + @push('js') + + @endpush + \ No newline at end of file From d636c9156735456f144beec81bfac4a8bca8a092 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Tue, 29 Apr 2025 20:43:21 +0800 Subject: [PATCH 091/298] Add orders resource route for seller management --- routes/web.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/routes/web.php b/routes/web.php index e7890ae..b5670c1 100644 --- a/routes/web.php +++ b/routes/web.php @@ -9,6 +9,7 @@ use App\Http\Controllers\DeliveryAddressController; use App\Http\Controllers\ProfileController; use App\Http\Controllers\Seller\CategoryController; +use App\Http\Controllers\Seller\OrderController; use App\Http\Controllers\Seller\ShippingController; use App\Livewire\Settings\Appearance; use App\Livewire\Settings\Password; @@ -47,6 +48,7 @@ Route::resource('products', ProductController::class)->except(['show']); Route::resource('categories', CategoryController::class)->except(['show']); Route::resource('shippings', ShippingController::class)->except(['show']); + Route::resource('orders', OrderController::class)->except(['show']); }); Route::middleware(['auth'])->prefix('profile')->name('profile.')->group(function () { From 65503e630d051478fe645c4f3328c7315478755b Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:38:15 +0800 Subject: [PATCH 092/298] GIANT REFACTOR OF PREFERENCE ALGORITHM --- app/Http/Controllers/BuyerController.php | 608 ++++++++++++++++++++--- 1 file changed, 536 insertions(+), 72 deletions(-) diff --git a/app/Http/Controllers/BuyerController.php b/app/Http/Controllers/BuyerController.php index eb87111..45b1b50 100644 --- a/app/Http/Controllers/BuyerController.php +++ b/app/Http/Controllers/BuyerController.php @@ -4,121 +4,585 @@ use App\Models\Product; use App\Models\UserCategoryPreference; +use App\Models\Category; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\DB; +use Carbon\Carbon; class BuyerController extends Controller { + // Constants for the recommendation algorithm + const RECENCY_WEIGHT = 0.3; // How much recent interactions matter (0-1) + const FREQUENCY_WEIGHT = 0.4; // How much interaction frequency matters (0-1) + const ENGAGEMENT_WEIGHT = 0.3; // How much deeper engagement matters (0-1) + const DECAY_FACTOR = 0.95; // Daily decay factor for preferences (0-1) + const CACHE_MINUTES = 60; // How long to cache recommendations + const MAX_RECOMMENDED_PRODUCTS = 10; // Maximum number of recommended products to show + /** - * Display a listing of the resource. + * Display a listing of the resource with improved recommendations. */ public function index() { $search = request('search'); $user = auth()->user(); - $preferredCategories = []; + $categoryFilter = request('category'); - // Get user's category preferences with weights + // Get recommended products and categories if ($user) { - $preferredCategories = $user->categoryPreferences() - ->orderByDesc('weight') - ->pluck('weight', 'category') - ->toArray(); + $recommended = $this->getRecommendedProducts($user); + $recommendedProducts = $recommended['products']; + $preferredCategories = $recommended['categories']; + $topCategory = $recommended['top_category']; + } else { + $recommendedProducts = collect(); + $preferredCategories = []; + $topCategory = null; } + // Handle search if ($search) { - $products = Product::query() - ->when($search, function($query, $search) { - return $query->where('name', 'like', '%' . $search . '%'); - }) - ->get(); - - // Adjust weights based on search frequency - if ($user && $products->count() > 0) { - // Count categories in search results - $categoryCounts = []; - foreach ($products as $product) { - if ($product->category) { - $categoryCounts[$product->category] = ($categoryCounts[$product->category] ?? 0) + 1; - } - } - // Increase weight for categories found, decrease for others - foreach ($categoryCounts as $category => $count) { - $pref = \App\Models\UserCategoryPreference::firstOrCreate( - ['user_id' => $user->id, 'category' => $category], - ['weight' => 0] - ); - $pref->increment('weight', $count); // Increase by frequency in search results - $preferredCategories[$category] = $pref->weight; - } - // Decay weights for categories not found in this search (by 1 per search, not by count) - //TODO- decay weights slower - $allCategories = array_keys($preferredCategories); - foreach ($allCategories as $category) { - if (!isset($categoryCounts[$category])) { - $pref = \App\Models\UserCategoryPreference::where([ - 'user_id' => $user->id, - 'category' => $category - ])->first(); - if ($pref && $pref->weight > 0) { - $pref->decrement('weight', 1); // Only decrement by 1 per search - $preferredCategories[$category] = $pref->weight; - } - } - } + $products = $this->handleSearchAndUpdatePreferences($search, $user); + + // Refresh recommendations after search + if ($user) { + Cache::forget("user_{$user->id}_recommendations"); + $recommended = $this->getRecommendedProducts($user); + $preferredCategories = $recommended['categories']; + $topCategory = $recommended['top_category']; + } + } + // Handle category filter + elseif ($categoryFilter) { + $products = Product::with('category') + ->where('category_id', $categoryFilter) + ->latest() + ->paginate(12); + } + // Show recommended or all products + else { + if ($user && $recommendedProducts->isNotEmpty()) { + $products = $recommendedProducts; + } else { + // Default to showing latest products for guests or users with no preferences + $products = Product::with('category') + ->latest() + ->paginate(12); } - } else { - $products = Product::all(); } - // Sort products by user's category weights - if ($user && count($preferredCategories)) { - $products = $products->sortByDesc(function($product) use ($preferredCategories) { - return $preferredCategories[$product->category] ?? 0; - })->values(); + // Get trending categories (most popular across all users) + $trendingCategories = $this->getTrendingCategories(); + + $recommendedCategoryName = null; + if ($topCategory) { + $catObj = Category::find($topCategory); + $recommendedCategoryName = $catObj ? $catObj->name : $topCategory; } - // Show the top preferred category (optional) - $topCategory = count($preferredCategories) ? array_key_first($preferredCategories) : null; + // Get all categories + $allCategories = Category::orderBy('name')->get(); return view('buyer.dashboard', [ 'products' => $products, 'recommendedCategory' => $topCategory, + 'recommendedCategoryName' => $recommendedCategoryName, + 'preferredCategories' => $preferredCategories, + 'trendingCategories' => $trendingCategories, + 'allCategories' => $allCategories, // Add this line + 'isSearchResults' => !empty($search), + 'searchTerm' => $search, ]); } + /** + * Get recommended products based on user preferences with collaborative filtering. + */ + private function getRecommendedProducts($user) + { + // Try to get from cache first + return Cache::remember("user_{$user->id}_recommendations", self::CACHE_MINUTES, function () use ($user) { + // Get user's category preferences + $userPreferences = $this->getUserCategoryScores($user); + + // If user has no preferences, return empty + if (empty($userPreferences)) { + return [ + 'products' => collect(), + 'categories' => [], + 'top_category' => null + ]; + } + + // Get categories sorted by preference score + $sortedCategories = $userPreferences; + arsort($sortedCategories); + + // Get products from preferred categories + $recommendedProducts = $this->getProductsFromPreferredCategories($sortedCategories); + + // Add collaborative filtering recommendations + $collaborativeRecommendations = $this->getCollaborativeRecommendations($user, $userPreferences); + + // Merge and remove duplicates + $allRecommendations = $recommendedProducts->merge($collaborativeRecommendations)->unique('id'); + + // Sort by relevance score and get paginated results + $finalRecommendations = $allRecommendations->sortByDesc('relevance_score')->take(self::MAX_RECOMMENDED_PRODUCTS); + + return [ + 'products' => $finalRecommendations, + 'categories' => $sortedCategories, + 'top_category' => key($sortedCategories) + ]; + }); + } + + /** + * Calculate personalized category scores based on recency, frequency and engagement. + */ + private function getUserCategoryScores($user) + { + // Get raw preferences + $preferences = UserCategoryPreference::where('user_id', $user->id) + ->where('weight', '>', 0) + ->get(); + + if ($preferences->isEmpty()) { + return []; + } + + $categoryScores = []; + + foreach ($preferences as $pref) { + // Get category information + $category = Category::find($pref->category_id); + if (!$category) continue; + + // Calculate recency factor - how recently did the user interact with this category + $daysSinceLastInteraction = $pref->updated_at->diffInDays(Carbon::now()); + $recencyFactor = pow(self::DECAY_FACTOR, $daysSinceLastInteraction); + + // Calculate final score using weights + $score = $pref->weight * $recencyFactor; + + $categoryScores[$category->id] = $score; + } + + return $categoryScores; + } + + /** + * Get products from preferred categories. + */ + private function getProductsFromPreferredCategories($sortedCategories) + { + $categoryIds = array_keys($sortedCategories); + $totalScore = array_sum($sortedCategories); + + // Get products from top categories + $products = Product::with('category') + ->whereIn('category_id', $categoryIds) + ->latest() + ->take(50) // Get a good sample to work with + ->get(); + + // Add relevance score to each product + return $products->map(function ($product) use ($sortedCategories, $totalScore) { + $categoryScore = $sortedCategories[$product->category_id] ?? 0; + $normalizedScore = $totalScore > 0 ? $categoryScore / $totalScore : 0; + + // Add freshness factor - newer products get a boost + $daysOld = $product->created_at->diffInDays(Carbon::now()) + 1; + $freshnessFactor = 1 / (log($daysOld + 2, 10) + 1); + + // Add rating factor if available + $ratingFactor = $product->rating ? ($product->rating / 5) : 0.5; + + // Calculate final relevance score (0-1) + $relevanceScore = ($normalizedScore * 0.6) + ($freshnessFactor * 0.2) + ($ratingFactor * 0.2); + + $product->relevance_score = $relevanceScore; + return $product; + }); + } + + /** + * Recommend products based on similar users' preferences (collaborative filtering). + */ + private function getCollaborativeRecommendations($user, $userPreferences) + { + // Find users with similar preferences + $similarUsers = $this->getSimilarUsers($user->id, $userPreferences); + + if (empty($similarUsers)) { + return collect(); + } + + // Get products that similar users liked but current user hasn't interacted with + $userCategoryIds = array_keys($userPreferences); + + $similarUserIds = array_keys($similarUsers); + + // Get categories that similar users like but current user hasn't explored + $recommendedCategories = UserCategoryPreference::whereIn('user_id', $similarUserIds) + ->whereNotIn('category_id', $userCategoryIds) + ->where('weight', '>', 10) // Only consider categories they really like + ->select('category_id', DB::raw('SUM(weight) as total_weight')) + ->groupBy('category_id') + ->orderByDesc('total_weight') + ->pluck('total_weight', 'category_id') + ->toArray(); + + if (empty($recommendedCategories)) { + return collect(); + } + + // Get products from these categories + $products = Product::whereIn('category_id', array_keys($recommendedCategories)) + ->latest() + ->take(20) + ->get(); + + // Calculate relevance score based on collaborative filtering + return $products->map(function ($product) use ($recommendedCategories, $similarUsers) { + $categoryWeight = $recommendedCategories[$product->category_id] ?? 0; + $maxWeight = max($recommendedCategories); + $normalizedCategoryWeight = $maxWeight > 0 ? $categoryWeight / $maxWeight : 0; + + // Add freshness and rating factors + $daysOld = $product->created_at->diffInDays(Carbon::now()) + 1; + $freshnessFactor = 1 / (log($daysOld + 2, 10) + 1); + $ratingFactor = $product->rating ? ($product->rating / 5) : 0.5; + + // Calculate score - slightly lower than direct preferences for exploration/diversity + $relevanceScore = ($normalizedCategoryWeight * 0.5) + ($freshnessFactor * 0.25) + ($ratingFactor * 0.25); + $product->relevance_score = $relevanceScore * 0.85; // Slight penalty vs. direct preferences + + return $product; + }); + } + + /** + * Find users with similar preferences to the current user. + */ + private function getSimilarUsers($userId, $userPreferences) + { + // Convert user preferences to category_id => weight array + $categoryIds = array_keys($userPreferences); + + // Find users who have preferences for the same categories + $potentialSimilarUsers = UserCategoryPreference::whereIn('category_id', $categoryIds) + ->where('user_id', '!=', $userId) + ->select('user_id') + ->distinct() + ->pluck('user_id') + ->toArray(); + + if (empty($potentialSimilarUsers)) { + return []; + } + + // Get their full preferences + $otherUserPreferences = UserCategoryPreference::whereIn('user_id', $potentialSimilarUsers) + ->get() + ->groupBy('user_id'); + + // Calculate similarity scores + $similarityScores = []; + + foreach ($otherUserPreferences as $otherUserId => $preferences) { + // Convert to category_id => weight array + $otherUserCategoryPrefs = []; + foreach ($preferences as $pref) { + $otherUserCategoryPrefs[$pref->category_id] = $pref->weight; + } + + // Calculate cosine similarity + $similarity = $this->calculateSimilarity($userPreferences, $otherUserCategoryPrefs); + + // Only consider if similarity is above threshold + if ($similarity > 0.2) { + $similarityScores[$otherUserId] = $similarity; + } + } + + // Sort by similarity (highest first) + arsort($similarityScores); + + // Return top 5 similar users + return array_slice($similarityScores, 0, 5, true); + } + + /** + * Calculate cosine similarity between two users' preferences. + */ + private function calculateSimilarity($userPrefs1, $userPrefs2) + { + // Get all category IDs from both users + $allCategoryIds = array_unique(array_merge(array_keys($userPrefs1), array_keys($userPrefs2))); + + // Calculate dot product and magnitudes + $dotProduct = 0; + $magnitude1 = 0; + $magnitude2 = 0; + + foreach ($allCategoryIds as $categoryId) { + $weight1 = $userPrefs1[$categoryId] ?? 0; + $weight2 = $userPrefs2[$categoryId] ?? 0; + + $dotProduct += $weight1 * $weight2; + $magnitude1 += $weight1 * $weight1; + $magnitude2 += $weight2 * $weight2; + } + + // Prevent division by zero + if ($magnitude1 == 0 || $magnitude2 == 0) { + return 0; + } + + // Return cosine similarity + return $dotProduct / (sqrt($magnitude1) * sqrt($magnitude2)); + } + + /** + * Get trending categories across all users. + */ + private function getTrendingCategories() + { + return Cache::remember('trending_categories', 60, function () { + return UserCategoryPreference::select('category_id', DB::raw('SUM(weight) as total_weight')) + ->groupBy('category_id') + ->orderByDesc('total_weight') + ->take(5) + ->get() + ->map(function ($preference) { + $category = Category::find($preference->category_id); + return [ + 'id' => $preference->category_id, + 'name' => $category ? $category->name : 'Unknown', + 'weight' => $preference->total_weight + ]; + }); + }); + } + + /** + * Handle search and update user preferences. + */ + private function handleSearchAndUpdatePreferences($search, $user) + { + // Get direct matches first - only search by name + $directMatches = Product::with('category') + ->where('name', 'like', '%' . $search . '%') + ->latest() + ->get(); + + // Get recommended products (if user is logged in) + $recommendedProducts = collect(); + if ($user) { + $recommended = $this->getRecommendedProducts($user); + $recommendedProducts = $recommended['products'] + ->reject(function($product) use ($directMatches) { + return $directMatches->contains('id', $product->id); + }); + } + + // Same pagination logic continues... + $directMatches = $directMatches->map(function($product) { + $product->is_direct_match = true; + return $product; + }); + + $recommendedProducts = $recommendedProducts->map(function($product) { + $product->is_direct_match = false; + return $product; + }); + + // Combine but maintain order (direct matches first) + $allProducts = $directMatches->concat($recommendedProducts); + + // Convert to paginator + $perPage = 12; + $currentPage = request()->get('page', 1); + $items = $allProducts->forPage($currentPage, $perPage); + + $paginator = new \Illuminate\Pagination\LengthAwarePaginator( + $items, + $allProducts->count(), + $perPage, + $currentPage, + ['path' => request()->url(), 'query' => request()->query()] + ); + + // Update preferences if user is logged in and products found + if ($user && $directMatches->isNotEmpty()) { + $this->updatePreferencesFromSearch($user, $directMatches, $search); + } + + return $paginator; + } + + /** + * Update user preferences based on search results. + */ + private function updatePreferencesFromSearch($user, $products, $searchTerm) + { + // Get category counts from search results + $categoryCounts = []; + foreach ($products as $product) { + if ($product->category_id) { + $categoryCounts[$product->category_id] = ($categoryCounts[$product->category_id] ?? 0) + 1; + } + } + + // Get all user's category preferences + $allCategories = UserCategoryPreference::where('user_id', $user->id) + ->pluck('category_id') + ->toArray(); + + // Apply different weight increments based on relevance + foreach ($categoryCounts as $categoryId => $count) { + // Calculate search relevance factor based on number of matches + $relevanceFactor = min(5, $count); + + // Store the search term and category association for future reference + $this->storeSearchTerm($user->id, $searchTerm, $categoryId, $relevanceFactor); + + // Update user preference + $preference = UserCategoryPreference::firstOrCreate( + ['user_id' => $user->id, 'category_id' => $categoryId], + ['weight' => 0] + ); + + // Higher increment if more products match + $preference->weight = min(100, $preference->weight + $relevanceFactor); + $preference->save(); + } + + // Apply decay to non-matching categories + foreach ($allCategories as $categoryId) { + if (!isset($categoryCounts[$categoryId])) { + $pref = UserCategoryPreference::where([ + 'user_id' => $user->id, + 'category_id' => $categoryId + ])->first(); + + if ($pref && $pref->weight > 0) { + $pref->weight = max(0, $pref->weight * self::DECAY_FACTOR); + $pref->save(); + } + } + } + + // Clear the recommendations cache + Cache::forget("user_{$user->id}_recommendations"); + } + + /** + * Store search term for future analysis (can be used for advanced recommendations). + */ + private function storeSearchTerm($userId, $searchTerm, $categoryId, $relevance) + { + // Store search terms for future analysis and smarter recommendations + \App\Models\SearchHistory::create([ + 'user_id' => $userId, + 'search_term' => $searchTerm, + 'category_id' => $categoryId, + 'relevance' => $relevance + ]); + } + + /** + * Show single product and record the view. + */ public function show(string $id) { $product = Product::findOrFail($id); $user = auth()->user(); - if ($user && $product->category) { - $pref = \App\Models\UserCategoryPreference::firstOrCreate( - ['user_id' => $user->id, 'category' => $product->category], + + if ($user && $product->category_id) { + // Record a view with higher weight than just a search result + $preference = UserCategoryPreference::firstOrCreate( + ['user_id' => $user->id, 'category_id' => $product->category_id], ['weight' => 0] ); - $pref->increment('weight'); + + // Product view gets higher weight than just appearing in search + $preference->weight = min(100, $preference->weight + 3); + $preference->save(); + + // Clear recommendations cache + Cache::forget("user_{$user->id}_recommendations"); } - // Logic to show the product details - return view('buyer.product-details', compact('product')); // Return the view for the product details + + // Get related products + $relatedProducts = $this->getRelatedProducts($product, $user); + + return view('buyer.product-details', [ + 'product' => $product, + 'relatedProducts' => $relatedProducts + ]); } - public function showAccount() + /** + * Get related products for product detail page. + */ + private function getRelatedProducts($product, $user = null) { - $user = auth()->user(); - $ordersCount = $user->orders()->count() ?? 0; - $reviewsCount = $user->reviews()->count() ?? 0; - $latestOrders = $user->orders()->latest()->take(5)->get(); - $deliveryAddresses = $user->deliveryAddresses; // Fetch all delivery addresses for the user + // Strategy for related products: + // 1. Same category as current product + // 2. If user logged in, consider their preferences too + $query = Product::where('id', '!=', $product->id) + ->where('category_id', $product->category_id) + ->latest(); - // Logic to show the buyer's account details - return view('buyer.account-profile', compact('user', 'ordersCount', 'reviewsCount', 'latestOrders','deliveryAddresses')); // Return the view for the buyer's account + // If user is logged in and has preferences, boost products from their other preferred categories + if ($user) { + $preferredCategories = UserCategoryPreference::where('user_id', $user->id) + ->where('category_id', '!=', $product->category_id) + ->where('weight', '>', 10) + ->pluck('category_id') + ->toArray(); + + if (!empty($preferredCategories)) { + // Use union to combine with products from preferred categories + $preferredQuery = Product::where('id', '!=', $product->id) + ->whereIn('category_id', $preferredCategories) + ->latest() + ->take(3); + + $query = $query->take(3)->union($preferredQuery); + } + } + + return $query->take(6)->get(); } - public function resetRecommendations(Request $request) + /** + * Reset user recommendations. + */ + public function resetRecommendations() { $user = auth()->user(); if ($user) { - $user->categoryPreferences()->delete(); + UserCategoryPreference::where('user_id', $user->id)->delete(); + Cache::forget("user_{$user->id}_recommendations"); } - return redirect()->route('buyer.dashboard')->with('status', 'Recommendations reset.'); + return redirect()->route('buyer.dashboard')->with('status', 'Recommendations have been reset.'); + } + + /** + * Show all categories with their products. + */ + public function allCategories() + { + $categories = \App\Models\Category::with('products')->get(); + return view('buyer.all-categories', [ + 'categories' => $categories, + ]); } + + // Other methods can remain the same... } From 4386798a43433f0e15ac73db7df10f9e6116d2bf Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:38:33 +0800 Subject: [PATCH 093/298] add relationships --- app/Models/Category.php | 13 +++++++++---- app/Models/Product.php | 5 +++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/Models/Category.php b/app/Models/Category.php index 4dcca22..1f4f426 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -1,12 +1,17 @@ hasMany(Product::class); + } +} diff --git a/app/Models/Product.php b/app/Models/Product.php index 30e5d48..fbe1c67 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -29,4 +29,9 @@ public function reviews() { return $this->hasMany(Review::class); } + + public function category() + { + return $this->belongsTo(Category::class); + } } From 10fd7b4eab890dca447248e87385c116ca517869 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:38:58 +0800 Subject: [PATCH 094/298] add relationships --- app/Models/User.php | 2 +- app/Models/UserCategoryPreference.php | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/Models/User.php b/app/Models/User.php index 6ddf172..8696d21 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -82,6 +82,6 @@ public function deliveryAddresses() public function categoryPreferences() { - return $this->hasMany(\App\Models\UserCategoryPreference::class); + return $this->hasMany(UserCategoryPreference::class); } } diff --git a/app/Models/UserCategoryPreference.php b/app/Models/UserCategoryPreference.php index c92dc3d..546a73a 100644 --- a/app/Models/UserCategoryPreference.php +++ b/app/Models/UserCategoryPreference.php @@ -3,13 +3,25 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Factories\HasFactory; class UserCategoryPreference extends Model { - protected $fillable = ['user_id', 'category', 'weight']; + use HasFactory; + + protected $fillable = [ + 'user_id', + 'category_id', + 'weight' + ]; public function user() { return $this->belongsTo(User::class); } -} + + public function category() + { + return $this->belongsTo(Category::class); + } +} \ No newline at end of file From 5b6377f99a0d93eede87c08b4f76917a0ccc16e1 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:40:02 +0800 Subject: [PATCH 095/298] modify factory to use category_id --- database/factories/ProductFactory.php | 58 ++++++++++----------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/database/factories/ProductFactory.php b/database/factories/ProductFactory.php index b09bbe1..33d50db 100644 --- a/database/factories/ProductFactory.php +++ b/database/factories/ProductFactory.php @@ -3,31 +3,26 @@ namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; -use Illuminate\Support\Arr; +use App\Models\User; +use App\Models\Category; class ProductFactory extends Factory { - /** - * Define the model's default state. - * - * @return array - */ public function definition(): array { - $categories = ['Electronics', 'Clothing', 'Home & Garden', 'Books', 'Toys', 'Sports', 'Beauty', 'Food']; + $category = Category::inRandomOrder()->first(); - // Try to get a random user ID from the users table - $userId = \App\Models\User::inRandomOrder()->value('id'); - - // If no users exist, create one using the factory - if (!$userId) { - $userId = \App\Models\User::factory()->create()->id; + // If no categories are seeded, throw a helpful error + if (!$category) { + throw new \Exception('No categories found. Please run CategorySeeder before seeding products.'); } + $userId = User::inRandomOrder()->value('id') ?? \App\Models\User::factory()->create()->id; + return [ 'name' => $this->faker->unique()->words(rand(1, 3), true), 'description' => $this->faker->paragraphs(rand(1, 3), true), - 'category' => Arr::random($categories), + 'category_id' => $category->id, 'price' => $this->faker->randomFloat(2, 1, 1000), 'stock' => $this->faker->numberBetween(0, 500), 'image' => 'storage/random' . rand(1, 6) . '.webp', @@ -37,40 +32,29 @@ public function definition(): array ]; } - /** - * Indicate that the product is out of stock - */ public function outOfStock(): static { - return $this->state(function (array $attributes) { - return [ - 'stock' => 0, - ]; - }); + return $this->state(fn(array $attributes) => ['stock' => 0]); } - /** - * Indicate that the product has a specific category - */ - public function inCategory(string $category): static + public function inCategory(string $categoryName): static { - return $this->state(function (array $attributes) use ($category) { - return [ - 'category' => $category, - ]; + return $this->state(function (array $attributes) use ($categoryName) { + $category = Category::where('name', $categoryName)->first(); + + if (!$category) { + throw new \Exception("Category '{$categoryName}' not found. Make sure it's seeded."); + } + + return ['category_id' => $category->id]; }); } - /** - * Indicate that the product has a discount price - */ public function discounted(float $percentage): static { return $this->state(function (array $attributes) use ($percentage) { $discount = $attributes['price'] * ($percentage / 100); - return [ - 'price' => $attributes['price'] - $discount, - ]; + return ['price' => $attributes['price'] - $discount]; }); } -} \ No newline at end of file +} From 8e446a3b67d24c593012bae9665d1a642eb8f8e5 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:40:30 +0800 Subject: [PATCH 096/298] debugging --- ...4_29_094244_create_ucp_scheme_log_dump.php | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 database/migrations/2025_04_29_094244_create_ucp_scheme_log_dump.php diff --git a/database/migrations/2025_04_29_094244_create_ucp_scheme_log_dump.php b/database/migrations/2025_04_29_094244_create_ucp_scheme_log_dump.php new file mode 100644 index 0000000..938053d --- /dev/null +++ b/database/migrations/2025_04_29_094244_create_ucp_scheme_log_dump.php @@ -0,0 +1,73 @@ +get(); + Log::info('UserCategoryPreference records count:', ['count' => $records->count()]); + + if ($records->count() > 0) { + Log::info('Sample record:', (array)$records->first()); + } + } else { + Log::warning('user_category_preferences table does not exist!'); + } + + // Check if categories table exists + if (Schema::hasTable('categories')) { + $categoryColumns = Schema::getColumnListing('categories'); + Log::info('Categories table columns:', $categoryColumns); + + $categories = DB::table('categories')->get(); + Log::info('Categories count:', ['count' => $categories->count()]); + + if ($categories->count() > 0) { + Log::info('Sample category:', (array)$categories->first()); + } + } else { + Log::warning('categories table does not exist!'); + } + + // Check Product model structure + if (Schema::hasTable('products')) { + $productColumns = Schema::getColumnListing('products'); + Log::info('Products table columns:', $productColumns); + + // Check if any products have category_id + if (in_array('category_id', $productColumns)) { + $productsWithCategory = DB::table('products') + ->whereNotNull('category_id') + ->count(); + + Log::info('Products with category_id:', ['count' => $productsWithCategory]); + } else { + Log::warning('Products table does not have category_id column!'); + } + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // Nothing to revert + } +}; \ No newline at end of file From 7b739bb4ba1dd985f351303e938bf94c951f2311 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:41:23 +0800 Subject: [PATCH 097/298] modify web --- routes/web.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/routes/web.php b/routes/web.php index a0c7474..60f2071 100644 --- a/routes/web.php +++ b/routes/web.php @@ -14,6 +14,11 @@ use App\Livewire\Settings\Password; use App\Livewire\Settings\Profile; use Illuminate\Support\Facades\Route; +use App\Models\Product; +use App\Models\Category; +use App\Models\UserCategoryPreference; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Schema; Route::get('/', function () { return redirect()->route('buyer.dashboard'); @@ -33,7 +38,7 @@ Route::get('settings/appearance', Appearance::class)->name('settings.appearance'); }); -Route::middleware(['auth', 'role:admin'])->prefix('admin')->name('admin.')->group(function () { +Route::middleware(['auth', 'role:admin'])->prefix('admin')->name('admin.')->group(function () { Route::get('/admin/dashboard', [AdminController::class, 'index'])->name('dashboard'); Route::get('/admin/manage-seller', [AdminController::class, 'showManageSeller'])->name('manage-seller'); Route::get('/admin/manage-buyer', [AdminController::class, 'showManageBuyer'])->name('manage-buyer'); @@ -75,4 +80,7 @@ Route::post('/buyer/reset-recommendations', [BuyerController::class, 'resetRecommendations'])->name('buyer.reset_recommendations')->middleware('auth'); -require __DIR__.'/auth.php'; +// Add this route for all categories +Route::get('/categories', [BuyerController::class, 'allCategories'])->name('buyer.all_categories'); + +require __DIR__ . '/auth.php'; From 9fba43c29b6cdaa0bff20390135eb2c6d5d1b44f Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:41:41 +0800 Subject: [PATCH 098/298] search histories table --- app/Models/SearchHistory.php | 46 +++++++++++++++++++ ...9_095603_create_search_histories_table.php | 37 +++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 app/Models/SearchHistory.php create mode 100644 database/migrations/2025_04_29_095603_create_search_histories_table.php diff --git a/app/Models/SearchHistory.php b/app/Models/SearchHistory.php new file mode 100644 index 0000000..90c0295 --- /dev/null +++ b/app/Models/SearchHistory.php @@ -0,0 +1,46 @@ +belongsTo(User::class); + } + + /** + * Get the category associated with this search. + */ + public function category() + { + return $this->belongsTo(Category::class); + } +} \ No newline at end of file diff --git a/database/migrations/2025_04_29_095603_create_search_histories_table.php b/database/migrations/2025_04_29_095603_create_search_histories_table.php new file mode 100644 index 0000000..c69f7b0 --- /dev/null +++ b/database/migrations/2025_04_29_095603_create_search_histories_table.php @@ -0,0 +1,37 @@ +id(); + $table->unsignedBigInteger('user_id'); + $table->string('search_term'); + $table->unsignedBigInteger('category_id')->nullable(); + $table->float('relevance')->default(1.0); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('category_id')->references('id')->on('categories')->onDelete('set null'); + + // Index for faster lookups + $table->index(['user_id', 'category_id']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('user_search_history'); + } +}; \ No newline at end of file From 36f2d10f586ecbf4dd81e1d35f4c04c53b0af338 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:42:31 +0800 Subject: [PATCH 099/298] use migration created by artisan instead of relying on created ones so it's actually rollback-able --- ...83302_add_weight_to_user_category_preference.php} | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) rename database/migrations/{2024_01_01_000002_add_weight_to_user_category_preferences_table.php => 2025_04_29_083302_add_weight_to_user_category_preference.php} (70%) diff --git a/database/migrations/2024_01_01_000002_add_weight_to_user_category_preferences_table.php b/database/migrations/2025_04_29_083302_add_weight_to_user_category_preference.php similarity index 70% rename from database/migrations/2024_01_01_000002_add_weight_to_user_category_preferences_table.php rename to database/migrations/2025_04_29_083302_add_weight_to_user_category_preference.php index 5fd7770..f78349b 100644 --- a/database/migrations/2024_01_01_000002_add_weight_to_user_category_preferences_table.php +++ b/database/migrations/2025_04_29_083302_add_weight_to_user_category_preference.php @@ -4,19 +4,25 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class AddWeightToUserCategoryPreferencesTable extends Migration +return new class extends Migration { + /** + * Run the migrations. + */ public function up() { Schema::table('user_category_preferences', function (Blueprint $table) { - $table->integer('weight')->default(1); + $table->decimal('weight', 10, 2)->default(0); }); } + /** + * Reverse the migrations. + */ public function down() { Schema::table('user_category_preferences', function (Blueprint $table) { $table->dropColumn('weight'); }); } -} +}; From ef13004190ab3a96e707a7d965922f8c403d43f0 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:42:50 +0800 Subject: [PATCH 100/298] add category_id and drop category --- ...5308_add_category_id_to_products_table.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 database/migrations/2025_04_29_085308_add_category_id_to_products_table.php diff --git a/database/migrations/2025_04_29_085308_add_category_id_to_products_table.php b/database/migrations/2025_04_29_085308_add_category_id_to_products_table.php new file mode 100644 index 0000000..7ca5f35 --- /dev/null +++ b/database/migrations/2025_04_29_085308_add_category_id_to_products_table.php @@ -0,0 +1,30 @@ +unsignedBigInteger('category_id')->nullable()->after('stock'); + $table->foreign('category_id')->references('id')->on('categories')->onDelete('set null'); + $table->dropColumn('category'); // only if you want to fully migrate + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('products', function (Blueprint $table) { + // + }); + } +}; From fbe8b863659689b724de45399e2b921fd26a679b Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:43:13 +0800 Subject: [PATCH 101/298] use category_id instead of category in ucp --- ...update_user_category_preferences_table.php | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 database/migrations/2025_04_29_093406_update_user_category_preferences_table.php diff --git a/database/migrations/2025_04_29_093406_update_user_category_preferences_table.php b/database/migrations/2025_04_29_093406_update_user_category_preferences_table.php new file mode 100644 index 0000000..defbfe9 --- /dev/null +++ b/database/migrations/2025_04_29_093406_update_user_category_preferences_table.php @@ -0,0 +1,53 @@ +dropColumn('category'); + }); + } + + // Only add the new column if it doesn't exist + if (!Schema::hasColumn('user_category_preferences', 'category_id')) { + Schema::table('user_category_preferences', function (Blueprint $table) { + // Add the foreign key column + $table->unsignedBigInteger('category_id')->after('user_id'); + + // Add foreign key constraint + $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); + }); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('user_category_preferences', function (Blueprint $table) { + if (Schema::hasColumn('user_category_preferences', 'category_id')) { + // Drop the foreign key constraint first + $table->dropForeign(['category_id']); + // Then drop the column + $table->dropColumn('category_id'); + } + + if (!Schema::hasColumn('user_category_preferences', 'category')) { + // Add back the original column + $table->string('category')->after('user_id'); + } + }); + } +}; \ No newline at end of file From ae367f1afde2d37fbd11949a5f0a4f31f038850a Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:43:23 +0800 Subject: [PATCH 102/298] category seeder --- database/seeders/CategorySeeder.php | 27 +++++++++++++++++++++++++++ database/seeders/DatabaseSeeder.php | 1 + 2 files changed, 28 insertions(+) create mode 100644 database/seeders/CategorySeeder.php diff --git a/database/seeders/CategorySeeder.php b/database/seeders/CategorySeeder.php new file mode 100644 index 0000000..602f94c --- /dev/null +++ b/database/seeders/CategorySeeder.php @@ -0,0 +1,27 @@ + 'Electronics'], + ['name' => 'Clothing'], + ['name' => 'Home & Garden'], + ['name' => 'Books'], + ['name' => 'Toys'], + ['name' => 'Sports'], + ['name' => 'Beauty'], + ['name' => 'Food'], + ]); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index da6cf25..bdd730f 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -15,6 +15,7 @@ public function run(): void $this->call([ RoleSeeder::class, UserSeeder::class, + CategorySeeder::class, ProductSeeder::class, ]); } From 4426cd5b1875af2832ecc692d163aad3bf26a462 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:43:38 +0800 Subject: [PATCH 103/298] old buyer dashboard --- resources/views/buyer/dashboard old.blade.php | 767 ++++++++++++++++++ 1 file changed, 767 insertions(+) create mode 100644 resources/views/buyer/dashboard old.blade.php diff --git a/resources/views/buyer/dashboard old.blade.php b/resources/views/buyer/dashboard old.blade.php new file mode 100644 index 0000000..c61f1ef --- /dev/null +++ b/resources/views/buyer/dashboard old.blade.php @@ -0,0 +1,767 @@ + + {{--
    +
    +
    +

    + Limited Time Offer!
    Up to 50% OFF!

    +

    Don't + Wait - Limited Stock at Unbeatable Prices!

    + Shop + Now +
    + +
    + +
    --}} + + + + + +
    +
    + +
    +
    + +

    Electronics

    + +
    + +
    + +
    + +
    + {{-- @if(isset($recommendedCategory) && $recommendedCategory) +
    + @csrf + +
    + @endif --}} +
    + {{-- fILTTERS --}} +
    + + + +
    +
    + + + @if(isset($recommendedCategory) && $recommendedCategory) +
    +

    + Recommended for you: {{ $recommendedCategoryName ?? $recommendedCategory }} +

    +
    + @endif +
    + {{-- Products are already ordered: recommended category first --}} + @foreach ($products as $product) +
    +
    + + + +
    + +
    + + + {{ $product->name }} +

    {{$product->category->name}}

    +
    +
    + @for ($i = 1; $i <= 5; $i++) + + @endfor +
    + +

    + {{ number_format($product->reviews->avg('rating'), 1) }} +

    +

    ({{ $product->reviews->count() }})

    +
    + + {{--
      +
    • + +

      Shipping Today

      +
    • + +
    • + +

      Best Price

      +
    • +
    --}} + +
    +

    RM{{ $product->price }}

    +
    + @csrf + + + + +
    +
    +
    +
    + @endforeach +
    +
    + +
    +
    + + {{-- +
    + +
    +
    \ No newline at end of file From 4b098c8df3dbc28bfbfb2961c3d78df6879bb4bd Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Tue, 29 Apr 2025 21:43:47 +0800 Subject: [PATCH 104/298] new buyer dashboard --- .../views/buyer/all-categories.blade.php | 29 + resources/views/buyer/dashboard.blade.php | 1243 ++++++----------- .../views/components/product-card.blade.php | 77 + 3 files changed, 565 insertions(+), 784 deletions(-) create mode 100644 resources/views/buyer/all-categories.blade.php create mode 100644 resources/views/components/product-card.blade.php diff --git a/resources/views/buyer/all-categories.blade.php b/resources/views/buyer/all-categories.blade.php new file mode 100644 index 0000000..1a11a7b --- /dev/null +++ b/resources/views/buyer/all-categories.blade.php @@ -0,0 +1,29 @@ + +
    +
    +

    All Categories

    +
    + @foreach($categories as $category) +
    +

    {{ $category->name }}

    + @if($category->products->count()) +
    + @foreach($category->products as $product) + + @endforeach +
    + @else +
    No products in this category.
    + @endif +
    + @endforeach +
    +
    +
    +
    diff --git a/resources/views/buyer/dashboard.blade.php b/resources/views/buyer/dashboard.blade.php index 5b436cb..17c2b4b 100644 --- a/resources/views/buyer/dashboard.blade.php +++ b/resources/views/buyer/dashboard.blade.php @@ -1,798 +1,473 @@ - {{--
    -
    -
    -

    - Limited Time Offer!
    Up to 50% OFF!

    -

    Don't - Wait - Limited Stock at Unbeatable Prices!

    - Shop - Now -
    - -
    - -
    --}} + +
    +
    + +
    +
    + + +

    + @if($isSearchResults) + Search Results for "{{ $searchTerm }}" + @elseif(request('category')) + @php + $categoryName = "Products"; + foreach($trendingCategories as $cat) { + if($cat['id'] == request('category')) { + $categoryName = $cat['name']; + break; + } + } + @endphp + {{ $categoryName }} + @elseif(isset($recommendedCategoryName) && $recommendedCategoryName) + Recommended For You + @else + All Products + @endif +

    - - - -
    -
    - -
    -
    - -

    Electronics

    - -
    - -
    - -
    - -
    - @if(isset($recommendedCategory) && $recommendedCategory) -
    - @csrf - -
    - @endif +
    +
    + +
    +
    +
    - {{-- fILTTERS --}} -
    - - - +
    -
    - - - @if(isset($recommendedCategory) && $recommendedCategory) -
    -

    - Recommended for you: {{ $recommendedCategory }} -

    -
    - @endif -
    - {{-- Products are already ordered: recommended category first --}} - @foreach ($products as $product) -
    - - -
    - - - {{ $product->name }} -

    {{$product->category}}

    -
    -
    - @for ($i = 1; $i <= 5; $i++) - - @endfor -
    - -

    - {{ number_format($product->reviews->avg('rating'), 1) }} -

    -

    ({{ $product->reviews->count() }})

    -
    - - {{--
      -
    • - -

      Shipping Today

      -
    • - -
    • - -

      Best Price

      -
    • -
    --}} - -
    -

    RM{{ $product->price }}

    - - @csrf - - - - - -
    + + + + +
    + + -
    - +
    +
    + + +
    +
    +

    Featured Categories

    + + View all + +
    + +
    + @if(isset($trendingCategories)) + @foreach($trendingCategories->take(6) as $category) + + {{ $category['name'] }} + @if(isset($category['count'])) + {{ $category['count'] }} products + @endif + + @endforeach + @endif +
    +
    + + + @if(isset($recommendedCategory) && $recommendedCategory && !$isSearchResults && !request('category')) +
    +
    +
    +
    +

    + Personalized for you: {{ $recommendedCategoryName }} +

    +
    + @csrf + +
    +
    + @endif +
    +
    + + +
    + @if($isSearchResults && $products->count() > 0) + + @php + $directMatches = $products->filter(function($product) { + return $product->is_direct_match ?? false; + }); + @endphp + + @if($directMatches->count() > 0) +

    Products Matching "{{ $searchTerm }}"

    +
    + @foreach($directMatches as $product) + @include('components.product-card', ['product' => $product]) + @endforeach +
    + @endif + + + @php + $recommendations = $products->filter(function($product) { + return !($product->is_direct_match ?? true); + }); + @endphp + + @if($recommendations->count() > 0) +

    Similar Products You Might Like

    +
    + @foreach($recommendations as $product) + @include('components.product-card', ['product' => $product]) + @endforeach +
    + @endif + @else +
    + @if($products->count() > 0) + @foreach($products as $product) + @include('components.product-card', ['product' => $product]) + @endforeach + @else +
    + + + +

    No products found

    +

    Try adjusting your search or filter to find what you're looking + for.

    + + View all products + +
    + @endif +
    + @endif +
    + + + @if($products->count() > 0) +
    + @if(method_exists($products, 'links') && !$products instanceof \Illuminate\Database\Eloquent\Collection) + {{ $products->links() }} + @else + + @endif +
    + @endif +
    +
    + + \ No newline at end of file diff --git a/resources/views/components/product-card.blade.php b/resources/views/components/product-card.blade.php new file mode 100644 index 0000000..8b8e27f --- /dev/null +++ b/resources/views/components/product-card.blade.php @@ -0,0 +1,77 @@ +
    +
    + + {{ $product->name }} + + + + +
    +
    + @csrf + + + +
    +
    + + + @if($product->category) + + {{ $product->category->name }} + + @endif + + + @if(isset($product->relevance_score) && $product->relevance_score > 0 && !($product->is_direct_match ?? false)) + + Recommended + + @endif +
    + +
    + +
    +
    + @for ($i = 1; $i <= 5; $i++) + + @endfor + + {{ number_format($product->reviews->avg('rating'), 1) }} ({{ $product->reviews->count() }}) + +
    +
    + + + + {{ $product->name }} + + + +
    + RM{{ $product->price }} +
    + @csrf + + + +
    +
    +
    +
    From 25d01671ec61b16cd7814c160f7eadc929d5a309 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Tue, 29 Apr 2025 23:56:10 +0800 Subject: [PATCH 105/298] Implement payment and delivery status update functionality for orders --- .../Controllers/Seller/OrderController.php | 53 +++++++++++++ app/Models/Order.php | 4 +- public/js/order-table.js | 74 +++++++++---------- public/js/update-order-status.js | 73 ++++++++++++++++++ resources/views/seller/orders.blade.php | 24 ++++-- routes/web.php | 3 + 6 files changed, 186 insertions(+), 45 deletions(-) create mode 100644 public/js/update-order-status.js diff --git a/app/Http/Controllers/Seller/OrderController.php b/app/Http/Controllers/Seller/OrderController.php index 2c8e306..05f124f 100644 --- a/app/Http/Controllers/Seller/OrderController.php +++ b/app/Http/Controllers/Seller/OrderController.php @@ -67,4 +67,57 @@ public function destroy(string $id) { // } + + public function updatePaymentStatus(Request $request, Order $order) +{ + try { + // Validate the request + $request->validate([ + 'payment_status' => 'required|string|in:pending,paid,failed', + ]); + + // Update the payment status + $order->update(['payment_status' => $request->payment_status]); + + session()->flash('success', 'Payment status updated successfully.'); + + // Return success response + return response()->json([ + 'message' => 'Payment status updated successfully.', + 'payment_status' => $order->payment_status, + ], 200); + } catch (\Exception $e) { + // Handle any unexpected errors + return response()->json([ + 'message' => 'Failed to update payment status.', + 'error' => $e->getMessage(), + ], 500); + } +} + +public function updateDeliveryStatus(Request $request, Order $order) +{ + + try { + // Validate the request + $request->validate([ + 'delivery_status' => 'required|string|in:Pending,Shipped,Delivered,Cancelled', + ]); + + // Update the delivery status + $order->update(['delivery_status' => $request->delivery_status]); + + // Return success response + return response()->json([ + 'message' => 'Delivery status updated successfully.', + 'delivery_status' => $order->delivery_status, + ], 200); + } catch (\Exception $e) { + // Handle any unexpected errors + return response()->json([ + 'message' => 'Failed to update delivery status.', + 'error' => $e->getMessage(), + ], 500); + } +} } diff --git a/app/Models/Order.php b/app/Models/Order.php index 46aba28..f67aa34 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -14,7 +14,9 @@ class Order extends Model 'seller_id', 'items', 'total', - 'status', + 'delivery_status', + 'payment_status', + 'payment_method', ]; protected $casts = [ diff --git a/public/js/order-table.js b/public/js/order-table.js index 2e371d9..865bdc0 100644 --- a/public/js/order-table.js +++ b/public/js/order-table.js @@ -81,10 +81,6 @@ const table = new simpleDatatables.DataTable("#order-table", { // "
    " : "" // ) + ` - -
    + From b1c14f459ecece5fabb9897dd773ccf639e9db04 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 30 Apr 2025 01:44:19 +0800 Subject: [PATCH 113/298] Add reviews resource routes and response functionality for sellers --- routes/web.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/routes/web.php b/routes/web.php index d2a7eba..b323d57 100644 --- a/routes/web.php +++ b/routes/web.php @@ -49,6 +49,8 @@ Route::resource('categories', CategoryController::class)->except(['show']); Route::resource('shippings', ShippingController::class)->except(['show']); Route::resource('orders', OrderController::class)->except(['show']); + Route::resource('reviews', ReviewController::class)->except(['show']); + Route::post('reviews/{review}', [ReviewController::class, 'respond'])->name('reviews.respond'); Route::post('orders/{order}/update-payment-status', [OrderController::class, 'updatePaymentStatus']); Route::post('orders/{order}/update-delivery-status', [OrderController::class, 'updateDeliveryStatus']); From 1c30cdf27ef6101b25ce5fa7cecd0ed345e45c83 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Wed, 30 Apr 2025 02:09:21 +0800 Subject: [PATCH 114/298] too much changes i forgot --- resources/views/buyer/dashboard.blade.php | 244 +++++++++++----------- 1 file changed, 121 insertions(+), 123 deletions(-) diff --git a/resources/views/buyer/dashboard.blade.php b/resources/views/buyer/dashboard.blade.php index 17c2b4b..ec039af 100644 --- a/resources/views/buyer/dashboard.blade.php +++ b/resources/views/buyer/dashboard.blade.php @@ -1,8 +1,7 @@ -
    -
    - +
    +
    - -
    + @@ -129,7 +134,8 @@ class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-30
    - + {{-- broken af --}} + {{--

    Featured Categories

    @@ -152,14 +158,14 @@ class="category-card flex flex-col items-center justify-center p-4 border border @endforeach @endif
    -
    +
    --}} @if(isset($recommendedCategory) && $recommendedCategory && !$isSearchResults && !request('category'))
    + class="recommendation-badge inline-flex items-center justify-center rounded-lg bg-primary-100 text-primary-800 dark:bg-primary-900 dark:text-primary-300">
    -
    +
    @if($isSearchResults && $products->count() > 0) - - @php - $directMatches = $products->filter(function($product) { - return $product->is_direct_match ?? false; - }); - @endphp - - @if($directMatches->count() > 0) -

    Products Matching "{{ $searchTerm }}"

    -
    - @foreach($directMatches as $product) - @include('components.product-card', ['product' => $product]) - @endforeach -
    - @endif + + @php + $directMatches = $products->filter(function($product) { + return $product->is_direct_match ?? false; + }); + @endphp - - @php - $recommendations = $products->filter(function($product) { - return !($product->is_direct_match ?? true); - }); - @endphp - - @if($recommendations->count() > 0) -

    Similar Products You Might Like

    -
    - @foreach($recommendations as $product) - @include('components.product-card', ['product' => $product]) - @endforeach -
    - @endif - @else -
    - @if($products->count() > 0) - @foreach($products as $product) - @include('components.product-card', ['product' => $product]) - @endforeach - @else -
    - - - -

    No products found

    -

    Try adjusting your search or filter to find what you're looking - for.

    - - View all products - -
    - @endif -
    + @if($directMatches->count() > 0) +

    Products Matching "{{ $searchTerm }}"

    +
    + @foreach($directMatches as $product) + @include('components.product-card', ['product' => $product]) + @endforeach +
    @endif -
    - - @if($products->count() > 0) -
    - @if(method_exists($products, 'links') && !$products instanceof \Illuminate\Database\Eloquent\Collection) - {{ $products->links() }} + + @php + $recommendations = $products->filter(function($product) { + return !($product->is_direct_match ?? true); + }); + @endphp + + @if($recommendations->count() > 0) +

    Similar Products You Might Like

    +
    + @foreach($recommendations as $product) + @include('components.product-card', ['product' => $product]) + @endforeach +
    + @endif @else - +
    + @if($products->count() > 0) + @foreach($products as $product) + @include('components.product-card', ['product' => $product]) + @endforeach + @else +
    + + + +

    No products found

    +

    Try adjusting your search or filter to find what you're looking + for.

    + + View all products + +
    + @endif +
    @endif -
    - @endif +
    + + +
    +
    + + + + + + + \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index b323d57..79b80d5 100644 --- a/routes/web.php +++ b/routes/web.php @@ -10,6 +10,7 @@ use App\Http\Controllers\ProfileController; use App\Http\Controllers\Seller\CategoryController; use App\Http\Controllers\Seller\OrderController; +use App\Http\Controllers\Seller\ReportController; use App\Http\Controllers\Seller\ShippingController; use App\Livewire\Settings\Appearance; use App\Livewire\Settings\Password; @@ -50,6 +51,7 @@ Route::resource('shippings', ShippingController::class)->except(['show']); Route::resource('orders', OrderController::class)->except(['show']); Route::resource('reviews', ReviewController::class)->except(['show']); + Route::resource('reports', ReportController::class)->except(['show']); Route::post('reviews/{review}', [ReviewController::class, 'respond'])->name('reviews.respond'); Route::post('orders/{order}/update-payment-status', [OrderController::class, 'updatePaymentStatus']); Route::post('orders/{order}/update-delivery-status', [OrderController::class, 'updateDeliveryStatus']); From 5970fb2e191e8920846a0dfb717ac462c85c067a Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Wed, 30 Apr 2025 19:02:48 +0800 Subject: [PATCH 123/298] tidy --- .../views/buyer/account-profile.blade.php | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/resources/views/buyer/account-profile.blade.php b/resources/views/buyer/account-profile.blade.php index 105b525..ae88180 100644 --- a/resources/views/buyer/account-profile.blade.php +++ b/resources/views/buyer/account-profile.blade.php @@ -1,10 +1,16 @@
    + +
    + + +
    +
    @csrf -
    +
    @if($user->avatar) Profile picture @@ -16,7 +22,6 @@
    @endif
    -

    {{ $user->name }}

    @@ -28,12 +33,6 @@ class="mt-1 block w-full text-sm border border-gray-300 rounded-lg cursor-pointe
    - -
    - - -
    -
    @@ -52,7 +51,7 @@ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-prima
    + class="mt-1 bg-gray-100 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 cursor-not-allowed dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500" value="Disabled input" disabled> @error('username')

    {{ $message }}

    @enderror @@ -104,6 +103,13 @@ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-prima
    + +
    + +
    +

    Delivery Addresses

    @@ -188,12 +194,7 @@ class="text-xs font-normal text-gray-500 dark:text-gray-300"> @endif
    - -
    - -
    +
    \ No newline at end of file From 0e70f8961ebf65070d5b897f97d41689a93bfe54 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 30 Apr 2025 19:14:10 +0800 Subject: [PATCH 124/298] Remove unused div for pie chart in sales report view --- resources/views/seller/reports.blade.php | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/views/seller/reports.blade.php b/resources/views/seller/reports.blade.php index 2e1a653..23fc52b 100644 --- a/resources/views/seller/reports.blade.php +++ b/resources/views/seller/reports.blade.php @@ -34,7 +34,6 @@ class="px-4 py-2 bg-pink-600 text-white rounded-lg hover:bg-pink-700 focus:outli

    Frequent Product Category Purchases

    - From 68dde8d7f6331716489c620986e02c8039e05ca3 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Thu, 1 May 2025 00:12:27 +0800 Subject: [PATCH 125/298] delete selection --- .../Controllers/Seller/ProductController.php | 17 ++++++++ public/js/product-table.js | 40 ++++++++++++++++++- routes/web.php | 3 +- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Seller/ProductController.php b/app/Http/Controllers/Seller/ProductController.php index c7b2dbb..c282166 100644 --- a/app/Http/Controllers/Seller/ProductController.php +++ b/app/Http/Controllers/Seller/ProductController.php @@ -98,4 +98,21 @@ public function show(Product $product) return view('product.product-view', compact('product','averageRating')); } + + public function deleteMultiple(Request $request) +{ + $request->validate([ + 'product_ids' => 'required|array', + 'product_ids.*' => 'exists:products,id', + ]); + + $productIds = $request->product_ids; + + // Ensure the products belong to the authenticated seller + Product::whereIn('id', $productIds) + ->where('seller_id', auth()->id()) + ->delete(); + + return response()->json(['message' => 'Selected products deleted successfully.']); +} } diff --git a/public/js/product-table.js b/public/js/product-table.js index 12c7fb4..9174171 100644 --- a/public/js/product-table.js +++ b/public/js/product-table.js @@ -172,10 +172,48 @@ table.on("datatable.selectrow", (rowIndex, event) => { console.log("Deleting rows:", selectedRows.map( id=>id )); - // Perform your delete logic here (e.g., send an AJAX request) + + deleteSelectedProducts(selectedRows); + + } } else { alert("No rows selected."); } }); + + // Function to delete selected products via AJAX +function deleteSelectedProducts(productIds) { + if (productIds.length === 0) { + alert("No products selected for deletion."); + return; + } + + if (confirm("Are you sure you want to delete the selected products?")) { + $.ajax({ + url: "/seller/products/delete-multiple", // Adjust the URL to match your route + type: "POST", + data: { + product_ids: productIds, // Pass the list of product IDs + _token: $('meta[name="csrf-token"]').attr('content') // Include CSRF token + }, + success: function (response) { + alert(response.message || "Products deleted successfully."); + // Refresh the table or remove the deleted rows + productIds.forEach(id => { + const row = document.querySelector(`#product-table tr[data-id="${id}"]`); + if (row) { + row.remove(); + } + }); + selectedRows = []; // Clear the selected rows array + document.getElementById("deleteSelectionButton").disabled = true; // Disable the delete button + }, + error: function (xhr, status, error) { + console.error("Error deleting products:", error); + alert("An error occurred while deleting the products. Please try again."); + } + }); + } +} }; \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 42fd6e0..65a000c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -55,7 +55,8 @@ Route::post('reviews/{review}', [ReviewController::class, 'respond'])->name('reviews.respond'); Route::post('orders/{order}/update-payment-status', [OrderController::class, 'updatePaymentStatus']); Route::post('orders/{order}/update-delivery-status', [OrderController::class, 'updateDeliveryStatus']); - + + Route::post('/products/delete-multiple', [ProductController::class, 'deleteMultiple'])->name('seller.products.delete-multiple'); }); Route::middleware(['auth'])->prefix('profile')->name('profile.')->group(function () { From ef2c9ad0465b3039040e0b8c94aca5b73d91f9b5 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Thu, 1 May 2025 00:12:42 +0800 Subject: [PATCH 126/298] add better UI --- .../views/buyer/account-profile.blade.php | 352 +++++++++--------- 1 file changed, 177 insertions(+), 175 deletions(-) diff --git a/resources/views/buyer/account-profile.blade.php b/resources/views/buyer/account-profile.blade.php index ae88180..2c13169 100644 --- a/resources/views/buyer/account-profile.blade.php +++ b/resources/views/buyer/account-profile.blade.php @@ -1,200 +1,202 @@
    +
    -
    - @csrf - - -
    -
    - @if($user->avatar) - Profile picture - @else -
    - - - + + @csrf + + +
    +
    + @if($user->avatar) + Profile picture + @else +
    + + + +
    + @endif +
    +
    +

    {{ $user->name }}

    +
    + + +

    PNG, JPG or GIF (MAX. 2MB)

    - @endif -
    -
    -

    {{ $user->name }}

    -
    - - -

    PNG, JPG or GIF (MAX. 2MB)

    -
    - - -
    - -
    -

    Basic Information

    - + + +
    +
    - {{-- NAME FIELD --}} -
    - - -
    - - {{-- USERNAME FIELD --}} -
    - - - @error('username') -

    {{ $message }}

    - @enderror -
    - - {{-- EMAIL FIELD --}} -
    - - - @error('email') -

    {{ $message }}

    - @enderror -
    - - {{-- PHONE NUMBER FIELD --}} -
    - - - @error('phone_number') -

    {{ $message }}

    - @enderror +

    Basic Information

    + +
    + {{-- NAME FIELD --}} +
    + + +
    + + {{-- USERNAME FIELD --}} +
    + + + @error('username') +

    {{ $message }}

    + @enderror +
    + + {{-- EMAIL FIELD --}} +
    + + + @error('email') +

    {{ $message }}

    + @enderror +
    + + {{-- PHONE NUMBER FIELD --}} +
    + + + @error('phone_number') +

    {{ $message }}

    + @enderror +
    -
    - - -
    -

    Security

    - - {{-- PASSWORD FIELDS --}} + +
    -
    - - - @error('password') -

    {{ $message }}

    - @enderror -
    - -
    - - +

    Security

    + + {{-- PASSWORD FIELDS --}} +
    +
    + + + @error('password') +

    {{ $message }}

    + @enderror +
    + +
    + + +
    -
    - - -
    - -
    - - -
    -

    Delivery Addresses

    -
    - -
    - - -
    -
    - - -
    -

    Latest Orders

    - {{-- Loop Order here --}} - @if ($latestOrders->isEmpty()) -

    No orders found.

    - @else - @foreach ($latestOrders as $order) - - @endforeach - - @endif -
    - - - + + +
    +

    Latest Orders

    + {{-- Loop Order here --}} + @if ($latestOrders->isEmpty()) +

    No orders found.

    + @else + @foreach ($latestOrders as $order) + + @endforeach + + @endif +
    + + + +
    \ No newline at end of file From 26890c6c31e66724af74ce9694730d3bd85bd6a8 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 00:29:00 +0800 Subject: [PATCH 127/298] hotfix --- .../views/buyer/account-profile.blade.php | 292 +++++++++++------- 1 file changed, 172 insertions(+), 120 deletions(-) diff --git a/resources/views/buyer/account-profile.blade.php b/resources/views/buyer/account-profile.blade.php index 2c13169..34d8e9a 100644 --- a/resources/views/buyer/account-profile.blade.php +++ b/resources/views/buyer/account-profile.blade.php @@ -1,202 +1,254 @@
    - - -
    - - -
    - -
    + + +
    + + +
    + + @csrf - +
    @if($user->avatar) - Profile picture + Profile picture @else -
    - - - -
    +
    + + + +
    @endif

    {{ $user->name }}

    - - -

    PNG, JPG or GIF (MAX. 2MB)

    + + +

    PNG, JPG or GIF (MAX. 5MB)

    - +

    Basic Information

    - +
    {{-- NAME FIELD --}}
    + class="block w-full rounded-lg border border-gray-300 bg-white p-2.5 text-sm text-gray-900 hover:bg-gray-50 focus:border-primary-500 focus:ring-4 focus:ring-primary-300 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder:text-gray-400 dark:hover:bg-gray-700 dark:focus:border-primary-500">
    - + {{-- USERNAME FIELD --}}
    + class="mt-1 bg-gray-100 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 cursor-not-allowed dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500" + value="Disabled input" disabled> @error('username') -

    {{ $message }}

    +

    {{ $message }}

    @enderror
    - + {{-- EMAIL FIELD --}}
    + class="block w-full rounded-lg border border-gray-300 bg-white p-2.5 text-sm text-gray-900 hover:bg-gray-50 focus:border-primary-500 focus:ring-4 focus:ring-primary-300 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder:text-gray-400 dark:hover:bg-gray-700 dark:focus:border-primary-500"> @error('email') -

    {{ $message }}

    +

    {{ $message }}

    @enderror
    - + {{-- PHONE NUMBER FIELD --}}
    - + @error('phone_number') -

    {{ $message }}

    +

    {{ $message }}

    @enderror
    - +

    Security

    - + {{-- PASSWORD FIELDS --}}
    + class="block w-full rounded-lg border border-gray-300 bg-white p-2.5 text-sm text-gray-900 hover:bg-gray-50 focus:border-primary-500 focus:ring-4 focus:ring-primary-300 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder:text-gray-400 dark:hover:bg-gray-700 dark:focus:border-primary-500"> @error('password') -

    {{ $message }}

    +

    {{ $message }}

    @enderror
    - +
    - + + class="block w-full rounded-lg border border-gray-300 bg-white p-2.5 text-sm text-gray-900 hover:bg-gray-50 focus:border-primary-500 focus:ring-4 focus:ring-primary-300 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder:text-gray-400 dark:hover:bg-gray-700 dark:focus:border-primary-500">
    - +
    -
    - - -
    -

    Delivery Addresses

    -
    - - -
    - - - - - -
    -

    Latest Orders

    - {{-- Loop Order here --}} - @if ($latestOrders->isEmpty()) -

    No orders found.

    - @else - @foreach ($latestOrders as $order) - +

    Latest Orders

    + {{-- Loop Order here --}} + @if ($latestOrders->isEmpty()) +

    No orders found.

    + @else + @foreach ($latestOrders as $order) + - @endforeach - - @endif + @endforeach + + @endif +
    + + + @include('buyer.edit-address-modal')
    \ No newline at end of file From dca1012428aaa3ecb6d7be474e510f4d883dd290 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 00:32:24 +0800 Subject: [PATCH 128/298] add errors and improve UX --- .../views/buyer/account-profile.blade.php | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/resources/views/buyer/account-profile.blade.php b/resources/views/buyer/account-profile.blade.php index 34d8e9a..c2577a9 100644 --- a/resources/views/buyer/account-profile.blade.php +++ b/resources/views/buyer/account-profile.blade.php @@ -1,4 +1,20 @@ + @if (session('success')) + + @endif + + @if ($errors->any()) + + @endif
    @@ -94,7 +110,7 @@ class="block w-full rounded-lg border border-gray-300 bg-white p-2.5 text-sm tex
    - @error('password')

    {{ $message }}

    @@ -105,7 +121,9 @@ class="block w-full rounded-lg border border-gray-300 bg-white p-2.5 text-sm tex +

    Leave blank to keep current password

    From 15e1f31dc6028de12a231ed7c118056fdc297b82 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 00:35:10 +0800 Subject: [PATCH 129/298] use readonly instead of disabled due to form requirements --- resources/views/buyer/account-profile.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/buyer/account-profile.blade.php b/resources/views/buyer/account-profile.blade.php index c2577a9..1302ff2 100644 --- a/resources/views/buyer/account-profile.blade.php +++ b/resources/views/buyer/account-profile.blade.php @@ -73,7 +73,7 @@ class="block w-full rounded-lg border border-gray-300 bg-white p-2.5 text-sm tex + value="Disabled input" readonly> @error('username')

    {{ $message }}

    @enderror From 33150ba3259cfdb7fa806a9941887a22af60de8d Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Thu, 1 May 2025 00:37:47 +0800 Subject: [PATCH 130/298] Implement multi-image upload for products and update related views and model --- .../Controllers/Seller/ProductController.php | 73 +++++++++--- app/Models/Product.php | 2 +- ...025_04_19_100614_create_products_table.php | 2 +- .../views/Modal/create-product.blade.php | 111 +++++++++++++++++ resources/views/seller/products.blade.php | 112 ++---------------- 5 files changed, 179 insertions(+), 121 deletions(-) create mode 100644 resources/views/Modal/create-product.blade.php diff --git a/app/Http/Controllers/Seller/ProductController.php b/app/Http/Controllers/Seller/ProductController.php index c282166..25d567a 100644 --- a/app/Http/Controllers/Seller/ProductController.php +++ b/app/Http/Controllers/Seller/ProductController.php @@ -39,15 +39,26 @@ public function store(Request $request) 'price' => 'required|numeric|min:0', 'stock' => 'required|integer|min:0', 'category' => 'required|string|max:255', - 'image' => 'nullable|image|max:2048', + 'images.*' => 'nullable|image|max:2048', ]); - if ($request->hasFile('image')) { - $validated['image'] = $request->file('image')->store('products', 'public'); + $imagePaths = []; + if ($request->hasFile('images')) { + foreach ($request->file('images') as $image) { + $imagePaths[] = $image->store('products', 'public'); + } } // Automatically assign the authenticated seller's ID $validated['seller_id'] = auth()->id(); - Product::create($validated); + Product::create([ + 'name' => $validated['name'], + 'description' => $validated['description'], + 'price' => $validated['price'], + 'stock' => $validated['stock'], + 'category' => $validated['category'], + 'seller_id' => $validated['seller_id'], + 'images' => json_encode($imagePaths), // Save images as JSON + ]); return redirect()->back()->with('success', 'Product created successfully.'); } @@ -86,6 +97,16 @@ public function update(Request $request, Product $product) */ public function destroy(Product $product) { + // Decode the JSON images field to get the list of image paths + if ($product->images) { + $images = json_decode($product->images, true); + foreach ($images as $image) { + // Delete each image from storage + \Storage::disk('public')->delete($image); + } + } + + // Delete the product from the database $product->delete(); return redirect()->route('seller.products.index')->with('success', 'Product deleted successfully.'); @@ -100,19 +121,33 @@ public function show(Product $product) } public function deleteMultiple(Request $request) -{ - $request->validate([ - 'product_ids' => 'required|array', - 'product_ids.*' => 'exists:products,id', - ]); - - $productIds = $request->product_ids; - - // Ensure the products belong to the authenticated seller - Product::whereIn('id', $productIds) - ->where('seller_id', auth()->id()) - ->delete(); - - return response()->json(['message' => 'Selected products deleted successfully.']); -} + { + $request->validate([ + 'product_ids' => 'required|array', + 'product_ids.*' => 'exists:products,id', + ]); + + $productIds = $request->product_ids; + + // Retrieve the products that belong to the authenticated seller + $products = Product::whereIn('id', $productIds) + ->where('seller_id', auth()->id()) + ->get(); + + foreach ($products as $product) { + // Decode the JSON images field to get the list of image paths + if ($product->images) { + $images = json_decode($product->images, true); + foreach ($images as $image) { + // Delete each image from storage + \Storage::disk('public')->delete($image); + } + } + + // Delete the product from the database + $product->delete(); + } + + return response()->json(['message' => 'Selected products and their images deleted successfully.']); + } } diff --git a/app/Models/Product.php b/app/Models/Product.php index 71ff7a0..16cd5df 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -14,7 +14,7 @@ class Product extends Model 'price', 'stock', 'category', - 'image', + 'images', 'rating' ]; diff --git a/database/migrations/2025_04_19_100614_create_products_table.php b/database/migrations/2025_04_19_100614_create_products_table.php index 529ba9e..f55dbb5 100644 --- a/database/migrations/2025_04_19_100614_create_products_table.php +++ b/database/migrations/2025_04_19_100614_create_products_table.php @@ -18,7 +18,7 @@ public function up(): void $table->text('category'); $table->decimal('price', 10, 2); $table->integer('stock'); - $table->string('image')->nullable(); + $table->json('images')->nullable(); // Add a JSON column for images $table->timestamps(); $table->foreignId('seller_id')->constrained('users')->onDelete('cascade'); }); diff --git a/resources/views/Modal/create-product.blade.php b/resources/views/Modal/create-product.blade.php new file mode 100644 index 0000000..e836260 --- /dev/null +++ b/resources/views/Modal/create-product.blade.php @@ -0,0 +1,111 @@ + + + + \ No newline at end of file diff --git a/resources/views/seller/products.blade.php b/resources/views/seller/products.blade.php index e7391cd..c82dae5 100644 --- a/resources/views/seller/products.blade.php +++ b/resources/views/seller/products.blade.php @@ -198,11 +198,18 @@ class="btn text-pink-500 hover:text-pink-700"> @foreach ($products as $product)
    @@ -249,102 +256,7 @@ class="btn text-pink-500 hover:text-pink-700"> - - + @include('Modal.create-product') @push('js') From 7446b781b8e05d60d99571ab663f3f936da77992 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 00:38:07 +0800 Subject: [PATCH 131/298] layout --- .../views/buyer/account-profile.blade.php | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/resources/views/buyer/account-profile.blade.php b/resources/views/buyer/account-profile.blade.php index 1302ff2..a63cbd6 100644 --- a/resources/views/buyer/account-profile.blade.php +++ b/resources/views/buyer/account-profile.blade.php @@ -1,21 +1,22 @@ - @if (session('success')) - - @endif - - @if ($errors->any()) - - @endif
    + @if (session('success')) + + @endif + + @if ($errors->any()) + + @endif +
    From beb3447df71711d64d5b4a38d2175498090d5355 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 01:13:22 +0800 Subject: [PATCH 132/298] now in json formatting --- database/factories/ProductFactory.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/database/factories/ProductFactory.php b/database/factories/ProductFactory.php index 33d50db..efdb830 100644 --- a/database/factories/ProductFactory.php +++ b/database/factories/ProductFactory.php @@ -25,7 +25,10 @@ public function definition(): array 'category_id' => $category->id, 'price' => $this->faker->randomFloat(2, 1, 1000), 'stock' => $this->faker->numberBetween(0, 500), - 'image' => 'storage/random' . rand(1, 6) . '.webp', + 'images' => json_encode(array_map( + fn() => 'storage/random' . rand(1, 6) . '.webp', + range(1, 3) + )), 'seller_id' => $userId, 'created_at' => $this->faker->dateTimeBetween('-1 year', 'now'), 'updated_at' => $this->faker->dateTimeBetween('-1 year', 'now'), From 486ee1253282ffafd17786043bd9a3c9dfbb9e98 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 01:13:40 +0800 Subject: [PATCH 133/298] decode json, use first image in array as thumbnail --- resources/views/components/product-card.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/components/product-card.blade.php b/resources/views/components/product-card.blade.php index 4b83438..dc38d29 100644 --- a/resources/views/components/product-card.blade.php +++ b/resources/views/components/product-card.blade.php @@ -2,9 +2,9 @@
    {{ $product->name }} + src="{{ asset(json_decode($product->images)[0]) }}" alt="{{ $product->name }}" /> + src="{{ asset(json_decode($product->images)[0]) }}" alt="{{ $product->name }}" />
    From fd22dfa890c973dce6bb4974c668c07e620e363a Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 01:13:59 +0800 Subject: [PATCH 134/298] use asset --- resources/views/partials/cart-items.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/partials/cart-items.blade.php b/resources/views/partials/cart-items.blade.php index 24362fc..f7352b7 100644 --- a/resources/views/partials/cart-items.blade.php +++ b/resources/views/partials/cart-items.blade.php @@ -10,7 +10,7 @@ @foreach($cart as $id => $item)
    - {{ $item['name'] }} + {{ $item['name'] }}

    {{ $item['name'] }}

    From 06f93b5828bd72e23432f6d41cc7c623e41b7df1 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 01:14:07 +0800 Subject: [PATCH 135/298] image carousel --- .../views/product/product-view.blade.php | 78 +++++++++++++++++-- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/resources/views/product/product-view.blade.php b/resources/views/product/product-view.blade.php index c2604b2..79f1c9d 100644 --- a/resources/views/product/product-view.blade.php +++ b/resources/views/product/product-view.blade.php @@ -1,18 +1,29 @@ + @if (session('success'))
    {{ session('success') }}
    @endif -
    - +
    - {{ $product->name }} - +
    + + + + + + {{ $product->name }} + +
    + +
    + @foreach(json_decode($product->images) as $img) + Thumbnail + @endforeach +
    @@ -107,8 +118,63 @@ class="ml-4 text-accent-content dark:text-white bg-primary-700 hover:bg-primary- @push('scripts') + + + @endpush \ No newline at end of file From acea14ddc89244ef2300e1c81fd2ccef4c443cf3 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Thu, 1 May 2025 01:17:01 +0800 Subject: [PATCH 136/298] Refactor product category handling: update validation, model, and views to use category_id instead of category --- app/Http/Controllers/Seller/ProductController.php | 4 ++-- app/Models/Product.php | 2 +- .../migrations/2025_04_19_100614_create_products_table.php | 2 +- .../2025_04_29_085308_add_category_id_to_products_table.php | 2 +- database/seeders/DatabaseSeeder.php | 2 +- resources/views/Modal/create-product.blade.php | 6 +++--- resources/views/seller/products.blade.php | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/Http/Controllers/Seller/ProductController.php b/app/Http/Controllers/Seller/ProductController.php index 25d567a..dedbc83 100644 --- a/app/Http/Controllers/Seller/ProductController.php +++ b/app/Http/Controllers/Seller/ProductController.php @@ -38,7 +38,7 @@ public function store(Request $request) 'description' => 'required|string', 'price' => 'required|numeric|min:0', 'stock' => 'required|integer|min:0', - 'category' => 'required|string|max:255', + 'category_id' => 'required|exists:categories,id', 'images.*' => 'nullable|image|max:2048', ]); @@ -55,7 +55,7 @@ public function store(Request $request) 'description' => $validated['description'], 'price' => $validated['price'], 'stock' => $validated['stock'], - 'category' => $validated['category'], + 'category_id' => $validated['category_id'], 'seller_id' => $validated['seller_id'], 'images' => json_encode($imagePaths), // Save images as JSON ]); diff --git a/app/Models/Product.php b/app/Models/Product.php index 0f6f738..c8bdccd 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -15,7 +15,7 @@ class Product extends Model 'seller_id', 'price', 'stock', - 'category', + 'category_id', 'images', 'rating' ]; diff --git a/database/migrations/2025_04_19_100614_create_products_table.php b/database/migrations/2025_04_19_100614_create_products_table.php index f55dbb5..fc7c949 100644 --- a/database/migrations/2025_04_19_100614_create_products_table.php +++ b/database/migrations/2025_04_19_100614_create_products_table.php @@ -15,7 +15,7 @@ public function up(): void $table->id(); $table->string('name'); $table->text('description'); - $table->text('category'); + // $table->text('category'); $table->decimal('price', 10, 2); $table->integer('stock'); $table->json('images')->nullable(); // Add a JSON column for images diff --git a/database/migrations/2025_04_29_085308_add_category_id_to_products_table.php b/database/migrations/2025_04_29_085308_add_category_id_to_products_table.php index 7ca5f35..75a96bd 100644 --- a/database/migrations/2025_04_29_085308_add_category_id_to_products_table.php +++ b/database/migrations/2025_04_29_085308_add_category_id_to_products_table.php @@ -14,7 +14,7 @@ public function up() Schema::table('products', function (Blueprint $table) { $table->unsignedBigInteger('category_id')->nullable()->after('stock'); $table->foreign('category_id')->references('id')->on('categories')->onDelete('set null'); - $table->dropColumn('category'); // only if you want to fully migrate + // $table->dropColumn('category'); // only if you want to fully migrate }); } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index bdd730f..06c40e2 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -16,7 +16,7 @@ public function run(): void RoleSeeder::class, UserSeeder::class, CategorySeeder::class, - ProductSeeder::class, + // ProductSeeder::class, ]); } } diff --git a/resources/views/Modal/create-product.blade.php b/resources/views/Modal/create-product.blade.php index e836260..9863f2a 100644 --- a/resources/views/Modal/create-product.blade.php +++ b/resources/views/Modal/create-product.blade.php @@ -70,13 +70,13 @@ class="block w-full p-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border bor
    - - diff --git a/resources/views/seller/products.blade.php b/resources/views/seller/products.blade.php index c82dae5..692a7d0 100644 --- a/resources/views/seller/products.blade.php +++ b/resources/views/seller/products.blade.php @@ -213,7 +213,7 @@ class="w-16 h-16 object-cover rounded"> @endif
    - + - - - + @@ -30,21 +28,9 @@ - - - + {{-- --}} @endforeach diff --git a/resources/views/cart/index.blade.php b/resources/views/cart/index.blade.php index d00f00c..831ca33 100644 --- a/resources/views/cart/index.blade.php +++ b/resources/views/cart/index.blade.php @@ -157,7 +157,7 @@ class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dar
    - ${{ number_format($productsTotal, 2) }} + RM{{ number_format($productsTotal, 2) }}
    @@ -166,7 +166,7 @@ class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dar
    Shipping Total
    - ${{ number_format($shippingTotal, 2) }} + RM{{ number_format($shippingTotal, 2) }}
    @@ -174,7 +174,7 @@ class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dar class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dark:border-gray-700">
    Grand Total
    - ${{ number_format($grandTotal, 2) }} + RM{{ number_format($grandTotal, 2) }}
    diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index 62f37bb..4e3bb10 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -29,13 +29,13 @@ class="fixed print:hidden top-0 left-0 z-40 w-64 h-screen transition-transform - {{-- ADMIN NAVIGATIONS --}} @hasrole('admin') - - - + + + @endhasrole {{-- SELLER NAVIGATIONS --}} @hasrole('seller') diff --git a/resources/views/components/layouts/customer-layout.blade.php b/resources/views/components/layouts/customer-layout.blade.php index 2894157..ce3d700 100644 --- a/resources/views/components/layouts/customer-layout.blade.php +++ b/resources/views/components/layouts/customer-layout.blade.php @@ -85,24 +85,27 @@ class="hidden z-10 w-56 divide-y divide-gray-100 overflow-hidden overflow-y-auto class="inline-flex w-full text-gray-500 dark:text-gray-400 items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600"> Hi, {{ Auth::user()->name }}!

    -
  • - My Account
  • -
  • - My Orders
  • -
  • - Settings
  • -
  • + @hasrole('buyer') + - Favourites
  • -
  • + @endrole + @hasrole('seller') + - Delivery Addresses
  • -
  • + @endrole + @hasrole('admin') + - Billing Data
  • + My Account + + @endrole + +
    diff --git a/resources/views/seller/reviews.blade.php b/resources/views/seller/reviews.blade.php index f5f76c8..04278dd 100644 --- a/resources/views/seller/reviews.blade.php +++ b/resources/views/seller/reviews.blade.php @@ -36,7 +36,7 @@
    From effbe4dba65be00e8b2c5886f8a08a1a2b9a4346 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Thu, 1 May 2025 23:51:37 +0800 Subject: [PATCH 144/298] Remove order status assignment and update button styles in cart view --- app/Http/Controllers/Buyer/CartController.php | 2 +- resources/views/cart/index.blade.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Buyer/CartController.php b/app/Http/Controllers/Buyer/CartController.php index d3f8268..97da6ab 100644 --- a/app/Http/Controllers/Buyer/CartController.php +++ b/app/Http/Controllers/Buyer/CartController.php @@ -92,7 +92,7 @@ public function checkout(Request $request) 'items' => $items, 'total' => $total, 'payment_method' => 'qr', - 'status' => 'Pending', + // 'status' => 'Pending', ]); Log::debug("Order created for seller_id: {$sellerId} with total: {$total}", $items); } diff --git a/resources/views/cart/index.blade.php b/resources/views/cart/index.blade.php index 831ca33..b30e465 100644 --- a/resources/views/cart/index.blade.php +++ b/resources/views/cart/index.blade.php @@ -89,7 +89,7 @@ class="btn-plus hover:cursor-pointer inline-flex h-5 w-5 shrink-0 items-center j
    -

    ${{ $item['price'] +

    RM{{ $item['price'] * $item['quantity'] }}

    @@ -184,7 +184,7 @@ class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dar @csrf From 428220172415ac89a4543b403227d05224c1d235 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Fri, 2 May 2025 23:45:14 +0800 Subject: [PATCH 145/298] Enhance checkout process: update cart quantities from JSON input, calculate shipping fees, and improve order creation logic --- app/Http/Controllers/Buyer/CartController.php | 61 +++++++++++++++---- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/Buyer/CartController.php b/app/Http/Controllers/Buyer/CartController.php index 97da6ab..b015080 100644 --- a/app/Http/Controllers/Buyer/CartController.php +++ b/app/Http/Controllers/Buyer/CartController.php @@ -68,40 +68,79 @@ public function add(Request $request) public function checkout(Request $request) { $cart = Session::get('cart', []); - Log::debug('Checkout initiated. Cart:', $cart); // <-- debugging log + Log::debug('Checkout initiated. Cart:', $cart); if (empty($cart)) { Log::debug('Cart is empty during checkout.'); return redirect()->back()->with('error', 'Your cart is empty!'); } + // Update cart quantities from JSON input (hidden inputs) + if ($request->has('cart')) { + $updated = $request->input('cart'); + foreach ($updated as $id => $data) { + if (isset($cart[$id])) { + $cart[$id]['quantity'] = (int)$data['quantity']; + } + } + Session::put('cart', $cart); + Log::debug('Updated cart with new quantities:', $cart); + } + + // Retrieve shipping selections: shipping[product_id] => shipping option id + $shippingSelected = $request->input('shipping', []); + // Group items by seller $groupedItems = []; foreach ($cart as $id => $item) { $product = Product::findOrFail($id); - $groupedItems[$product->seller_id][] = $item; + $groupedItems[$product->seller_id][$id] = $item; } - Log::debug('Grouped cart items by seller:', $groupedItems); // <-- debugging log + Log::debug('Grouped cart items by seller:', $groupedItems); - // Create orders for each seller + // Create orders for each seller using recalculated totals including shipping fees. foreach ($groupedItems as $sellerId => $items) { - $total = array_sum(array_map(fn($item) => $item['price'] * $item['quantity'], $items)); + $productSubtotal = 0; + $shippingTotal = 0; + // Loop each item by reference to attach shipping_id + foreach ($items as $id => &$item) { + $productSubtotal += $item['price'] * $item['quantity']; + if (isset($shippingSelected[$id])) { + $item['shipping_id'] = $shippingSelected[$id]; + $shippingOption = Shipping::find($shippingSelected[$id]); + if ($shippingOption) { + $shippingTotal += $shippingOption->shipping_fee * $item['quantity']; + } + } else { + $item['shipping_id'] = null; + } + } + unset($item); // Break reference + + $grandTotal = $productSubtotal + $shippingTotal; + + $orderItems = [ + 'delivery_address_id' => $request->input('delivery_address'), + 'cart_items' => $items, + 'shipping_total' => $shippingTotal, + ]; + Order::create([ 'buyer_id' => Auth::id(), 'seller_id' => $sellerId, - 'items' => $items, - 'total' => $total, - 'payment_method' => 'qr', - // 'status' => 'Pending', + 'items' => $orderItems, + 'total' => $grandTotal, + 'payment_method' => $request->input('payment_method', 'qr'), + 'status' => 'Pending', ]); - Log::debug("Order created for seller_id: {$sellerId} with total: {$total}", $items); + Log::debug("Order created for seller_id: {$sellerId} with grand total: {$grandTotal}", $items); } // Clear the cart Session::forget('cart'); Log::debug('Cart cleared after checkout.'); - return redirect()->back()->with('success', 'Order placed successfully!'); + return redirect()->route('buyer.dashboard')->with('success', 'Order placed successfully!'); } public function remove($id) From 1a8d023b56260ee197808d58723562807b4715e3 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Fri, 2 May 2025 23:45:33 +0800 Subject: [PATCH 146/298] add success --- resources/views/buyer/dashboard.blade.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/views/buyer/dashboard.blade.php b/resources/views/buyer/dashboard.blade.php index ed43e25..993c19b 100644 --- a/resources/views/buyer/dashboard.blade.php +++ b/resources/views/buyer/dashboard.blade.php @@ -1,6 +1,11 @@
    + @if (session('success')) +
    + {{ session('success') }} +
    + @endif
    From 55c67493fa0a20a71e44a9adf359ff912e31e5d9 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Fri, 2 May 2025 23:45:38 +0800 Subject: [PATCH 147/298] Enhance cart functionality: add delivery address selection, update shipping options, and improve checkout process with dynamic pricing --- resources/views/cart/index.blade.php | 177 ++++++++++++++++++--------- 1 file changed, 120 insertions(+), 57 deletions(-) diff --git a/resources/views/cart/index.blade.php b/resources/views/cart/index.blade.php index b30e465..61f634b 100644 --- a/resources/views/cart/index.blade.php +++ b/resources/views/cart/index.blade.php @@ -3,31 +3,17 @@

    Shopping Cart

    - -
    - @if($addresses->isEmpty()) -
    - Warning: You have no delivery addresses. Please add one. -
    - @endif -
    - - -
    -
    + + @php + // Determine if any cart item has no shipping options + $disableCheckout = false; + foreach($cartItems as $item) { + if($item['shippings']->isEmpty()){ + $disableCheckout = true; + break; + } + } + @endphp
    @@ -89,8 +75,12 @@ class="btn-plus hover:cursor-pointer inline-flex h-5 w-5 shrink-0 items-center j
    -

    RM{{ $item['price'] - * $item['quantity'] }}

    + +

    + +

    + RM{{ number_format($item['price'] * $item['quantity'], 2) }} +

    @@ -112,11 +102,16 @@ class="shipping-select hover:cursor-pointer mt-2 bg-gray-50 border border-gray-3 @foreach ($item['shippings'] as $shipping) @endforeach
    + @else +
    + This item is not available for the time being +
    @endif
    @@ -136,21 +131,18 @@ class="shipping-select hover:cursor-pointer mt-2 bg-gray-50 border border-gray-3 - +

    Order summary

    -
    Total Items
    {{ count($cartItems) - }} -
    + }}
    -
    Products Total @@ -160,7 +152,6 @@ class="text-base font-medium text-gray-900 dark:text-white"> RM{{ number_format($productsTotal, 2) }}
    -
    Shipping Total @@ -169,7 +160,6 @@ class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dar RM{{ number_format($shippingTotal, 2) }}
    -
    Grand Total
    @@ -180,12 +170,60 @@ class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dar
    - + @csrf + +
    + @if($addresses->isEmpty()) +
    + Warning: You have no delivery addresses. Please add one. +
    + @endif +
    + + +
    +
    + + + @foreach($cartItems as $id => $item) + + + + @endforeach +
    + + +
    @@ -195,32 +233,42 @@ class="{{ $addresses->isEmpty() ? 'hover:cursor-not-allowed text-white bg-pink-4
    - - From bb5a1c3cc4c2c2d3ba9c50ccb996dce443839a74 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Sat, 3 May 2025 01:33:06 +0800 Subject: [PATCH 150/298] contact page --- app/Http/Controllers/ContactController.php | 25 ++++++ resources/views/contact/index.blade.php | 93 ++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 app/Http/Controllers/ContactController.php create mode 100644 resources/views/contact/index.blade.php diff --git a/app/Http/Controllers/ContactController.php b/app/Http/Controllers/ContactController.php new file mode 100644 index 0000000..2f97110 --- /dev/null +++ b/app/Http/Controllers/ContactController.php @@ -0,0 +1,25 @@ +validate([ + 'name' => 'required|string', + 'email' => 'required|email', + 'subject' => 'required|string|max:255', + 'message' => 'required|string', + ]); + + return back()->with('success', 'Your message has been sent successfully!'); + } +} diff --git a/resources/views/contact/index.blade.php b/resources/views/contact/index.blade.php new file mode 100644 index 0000000..5842975 --- /dev/null +++ b/resources/views/contact/index.blade.php @@ -0,0 +1,93 @@ + +
    +
    +
    + + +
    +

    Let's Talk

    +

    + Have questions? Feel free to contact us using the form or the details + below. +

    +
      +
    • + 📍 + Address: 123 Main Street, YourCity, Country +
    • +
    • + 📞 + Phone: +1 (555) 123-4567 +
    • +
    • + ✉️ + Email: support@example.com +
    • +
    • + 🕒 + Hours: Mon–Fri, 9AM–6PM +
    • +
    +
    + + +
    +

    Contact Us

    + + @if(session('success')) +
    + {{ session('success') }} +
    + @endif + +
    + @csrf + + +
    + + + @error('name')

    {{ $message }}

    @enderror +
    + + +
    + + + @error('email')

    {{ $message }}

    @enderror +
    + + +
    + + + @error('subject')

    {{ $message }}

    @enderror +
    + + +
    + + + @error('message')

    {{ $message }}

    @enderror +
    + + + + +
    +
    +
    +
    +
    \ No newline at end of file From bbfc3573917b80c0e4d391ca9c1c6d837870fc7d Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Sat, 3 May 2025 01:33:35 +0800 Subject: [PATCH 151/298] add product category filter on header --- .../layouts/customer-layout.blade.php | 114 +++++++----------- 1 file changed, 44 insertions(+), 70 deletions(-) diff --git a/resources/views/components/layouts/customer-layout.blade.php b/resources/views/components/layouts/customer-layout.blade.php index de0843a..c4dce6c 100644 --- a/resources/views/components/layouts/customer-layout.blade.php +++ b/resources/views/components/layouts/customer-layout.blade.php @@ -39,35 +39,29 @@ class="flex text-sm font-medium px-2 py-2.5 text-gray-900 hover:text-primary-700
  • - - +
  • - Contact @@ -281,64 +275,44 @@ class="inline-flex items-center justify-center w-10 h-10 rounded-full bg-white/3 {{ $slot }} From 8ea5f745f28fa81fea533aeaa3ec56008efa28f4 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Sat, 3 May 2025 01:33:53 +0800 Subject: [PATCH 152/298] add contact page --- routes/web.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/routes/web.php b/routes/web.php index 0683cd9..4d59303 100644 --- a/routes/web.php +++ b/routes/web.php @@ -9,6 +9,7 @@ use App\Http\Controllers\Seller\ProductController; use App\Http\Controllers\Buyer\CartController; use App\Http\Controllers\Buyer\ReviewController; +use App\Http\Controllers\ContactController; use App\Http\Controllers\DeliveryAddressController; use App\Http\Controllers\ProfileController; use App\Http\Controllers\Seller\CategoryController; @@ -41,6 +42,9 @@ Route::get('settings/profile', Profile::class)->name('settings.profile'); Route::get('settings/password', Password::class)->name('settings.password'); Route::get('settings/appearance', Appearance::class)->name('settings.appearance'); + + Route::get('/contact', [ContactController::class, 'show'])->name('contact.index'); + Route::post('/contact', [ContactController::class, 'submit'])->name('contact.submit'); }); Route::middleware(['auth', 'role:admin'])->prefix('admin')->name('admin.')->group(function () { From 667e31ff1b1cc3f84c06916cce1b3f698b9ab071 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Sat, 3 May 2025 02:31:30 +0800 Subject: [PATCH 153/298] invoice page --- app/Http/Controllers/BuyerController.php | 9 +++ resources/views/invoice.blade.php | 87 ++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 resources/views/invoice.blade.php diff --git a/app/Http/Controllers/BuyerController.php b/app/Http/Controllers/BuyerController.php index aa74179..eebf8ba 100644 --- a/app/Http/Controllers/BuyerController.php +++ b/app/Http/Controllers/BuyerController.php @@ -656,4 +656,13 @@ public function updateProfile(Request $request) return redirect()->back()->with('success', 'Profile updated successfully.'); } + + public function showInvoice(\App\Models\Order $order) + { + // Ensure the order belongs to the authenticated buyer + if (auth()->id() !== $order->buyer_id) { + abort(403, 'Unauthorized access to invoice.'); + } + return view('invoice', compact('order')); + } } diff --git a/resources/views/invoice.blade.php b/resources/views/invoice.blade.php new file mode 100644 index 0000000..efde748 --- /dev/null +++ b/resources/views/invoice.blade.php @@ -0,0 +1,87 @@ + +
    +
    + + + +
    +

    Invoice

    +

    Order Summary & Payment Details

    +
    + +
    +
    +
    +

    Order Details

    +
      +
    • Order ID: {{ $order->id }}
    • +
    • Date: {{ $order->created_at->format('M d, Y') }}
    • +
    • Payment Status: + + {{ $order->delivery_status }} + +
    • +
    • Delivery Status: + + {{ $order->delivery_status }} + +
    • +
    +
    + +
    +

    Billing Info

    +
      +
    • Buyer: {{ $order->buyer->name ?? 'Guest' }}
    • +
    • Seller: {{ $order->seller->name ?? 'Seller' }}
    • +
    • Payment: {{ ($order->payment_method == + 'online_banking' ? 'Online Banking' : 'QR Payment') }}
    • +
    • Total: RM{{ number_format($order->total, 2) }}
    • +
    +
    +
    + +

    Purchased Items

    +
    +
  • - @if ($product->image) - {{ $product->name }} + @if ($product->images) + @php + $images = json_decode($product->images, true); // Decode the JSON string + @endphp + @if (!empty($images) && isset($images[0])) + {{ $product->name }} + @else + No Image + @endif @else - No Image + No Image @endif {{ $product->name }} {{ $product->name }} {{ $product->category }} {{ $product->category->name ?? 'Unavalaible'}} RM{{ $product->price }} {{ $product->description }} {{ $product->reviews->avg('rating') ? $product->reviews->avg('rating') : 'No reviews yet' }} From e10b70d643ee113724bd5f9dbf5f0d8b72e271ba Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 01:19:37 +0800 Subject: [PATCH 137/298] cart use json object 0 for images --- app/Http/Controllers/Buyer/CartController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Buyer/CartController.php b/app/Http/Controllers/Buyer/CartController.php index d734077..7403210 100644 --- a/app/Http/Controllers/Buyer/CartController.php +++ b/app/Http/Controllers/Buyer/CartController.php @@ -22,6 +22,7 @@ public function index() public function add(Request $request) { $product = Product::findOrFail($request->product_id); + $productThumbnail = json_decode($product->images)[0]; $cart = Session::get('cart', []); if (isset($cart[$product->id])) { @@ -32,7 +33,7 @@ public function add(Request $request) 'price' => $product->price, 'category' => $product->category, 'quantity' => $request->quantity, - 'image' => $product->image, + 'image' => $productThumbnail, ]; } From 50bbf1a68e2a14d95316b37bd253fb98ee3e1af8 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Thu, 1 May 2025 02:00:29 +0800 Subject: [PATCH 138/298] Add ListOrder, Rating, and Transaction controllers with basic CRUD methods and routes --- .../Controllers/Admin/ListOrderController.php | 66 +++++++++++++++++ .../Controllers/Admin/RatingController.php | 66 +++++++++++++++++ .../Admin/TransactionController.php | 70 +++++++++++++++++++ routes/web.php | 7 ++ 4 files changed, 209 insertions(+) create mode 100644 app/Http/Controllers/Admin/ListOrderController.php create mode 100644 app/Http/Controllers/Admin/RatingController.php create mode 100644 app/Http/Controllers/Admin/TransactionController.php diff --git a/app/Http/Controllers/Admin/ListOrderController.php b/app/Http/Controllers/Admin/ListOrderController.php new file mode 100644 index 0000000..bf94fc0 --- /dev/null +++ b/app/Http/Controllers/Admin/ListOrderController.php @@ -0,0 +1,66 @@ +get(); + $orders = Order::where('payment_status', 'paid')->get(); + + return view('admin.transactions', compact('orders')); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + // + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + // + } + + /** + * Display the specified resource. + */ + public function show(string $id) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(string $id) + { + // + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, string $id) + { + // + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(string $id) + { + // + } +} diff --git a/routes/web.php b/routes/web.php index d217a8e..0683cd9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,5 +1,8 @@ name('dashboard'); Route::get('/admin/manage-seller', [AdminController::class, 'showManageSeller'])->name('manage-seller'); Route::get('/admin/manage-buyer', [AdminController::class, 'showManageBuyer'])->name('manage-buyer'); + + Route::resource('transactions', TransactionController::class)->except(['show']); + Route::resource('ratings', RatingController::class)->except(['show']); + Route::resource('orders', ListOrderController::class)->except(['show']); }); From 8f469df1c8a6df99e0b3d1321c2ca636a414e536 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Thu, 1 May 2025 02:00:42 +0800 Subject: [PATCH 139/298] Refactor UI components: update color scheme to use pink accents across various views and components --- resources/views/Modal/add-shipping.blade.php | 2 +- .../views/Modal/create-product.blade.php | 2 +- resources/views/admin/orders.blade.php | 8 +++ resources/views/admin/ratings.blade.php | 8 +++ resources/views/admin/transactions.blade.php | 54 +++++++++++++++++++ .../views/buyer/account-profile.blade.php | 6 +-- resources/views/buyer/dashboard old.blade.php | 4 +- resources/views/buyer/dashboard.blade.php | 2 +- .../views/components/dropdown-item.blade.php | 6 +-- .../components/layouts/app/sidebar.blade.php | 3 ++ .../views/components/paginator.blade.php | 2 +- .../views/components/product-card.blade.php | 4 +- resources/views/partials/cart-items.blade.php | 2 +- resources/views/seller/categories.blade.php | 2 +- resources/views/seller/orders.blade.php | 4 +- resources/views/welcome.blade.php | 30 +++++------ 16 files changed, 106 insertions(+), 33 deletions(-) create mode 100644 resources/views/admin/orders.blade.php create mode 100644 resources/views/admin/ratings.blade.php create mode 100644 resources/views/admin/transactions.blade.php diff --git a/resources/views/Modal/add-shipping.blade.php b/resources/views/Modal/add-shipping.blade.php index 8d75733..bed226d 100644 --- a/resources/views/Modal/add-shipping.blade.php +++ b/resources/views/Modal/add-shipping.blade.php @@ -35,7 +35,7 @@ class="block w-full p-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border bor
    RM
    - + @@ -185,7 +185,7 @@ class="text-xs font-normal text-gray-500 dark:text-gray-300">
    + class="w-4 h-4 text-pink-600 bg-gray-100 border-gray-300 focus:ring-pink-500 dark:focus:ring-pink-600 dark:ring-offset-gray-700 dark:focus:ring-offset-gray-700 focus:ring-2 dark:bg-gray-600 dark:border-gray-500">
    diff --git a/resources/views/seller/orders.blade.php b/resources/views/seller/orders.blade.php index d96b85c..932a05b 100644 --- a/resources/views/seller/orders.blade.php +++ b/resources/views/seller/orders.blade.php @@ -106,14 +106,14 @@ class="absolute invisible inline-block px-3 py-2 text-sm font-medium text-white RM{{ number_format($order->total, 2) }} {{ $order->payment_method }} - - diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index cea1636..5c629d4 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -5,23 +5,23 @@ @endsection From 18abbc76bd1da4cd27f7fc925004b69361df59e8 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 02:49:38 +0800 Subject: [PATCH 140/298] add seller id --- app/Models/Shipping.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Shipping.php b/app/Models/Shipping.php index 19535e2..9781d26 100644 --- a/app/Models/Shipping.php +++ b/app/Models/Shipping.php @@ -7,6 +7,6 @@ class Shipping extends Model { // - protected $fillable = ['place', 'shipping_fee']; // Allow mass assignment for these fields + protected $fillable = ['place', 'shipping_fee', 'seller_id']; // Allow mass assignment for these fields } From 2749227a0582fb1933868520469983990659f091 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 02:50:21 +0800 Subject: [PATCH 141/298] logging, add functionalities to cart index and hotfix index view returning --- app/Http/Controllers/Buyer/CartController.php | 30 ++- resources/views/cart/index.blade.php | 216 +++++++++++++++--- 2 files changed, 209 insertions(+), 37 deletions(-) diff --git a/app/Http/Controllers/Buyer/CartController.php b/app/Http/Controllers/Buyer/CartController.php index 7403210..d3f8268 100644 --- a/app/Http/Controllers/Buyer/CartController.php +++ b/app/Http/Controllers/Buyer/CartController.php @@ -5,9 +5,11 @@ use App\Http\Controllers\Controller; use App\Models\Order; use App\Models\Product; +use App\Models\Shipping; // <-- added for shipping lookup use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Session; +use Illuminate\Support\Facades\Log; // <-- added for debugging class CartController extends Controller { @@ -16,7 +18,22 @@ class CartController extends Controller public function index() { $cart = Session::get('cart', []); - return view('partials.cart-items', compact('cart')); + + // Prepare cart items with shipping options and default shipping fee + $cartItems = []; + foreach ($cart as $id => $item) { + $shippings = Shipping::where('seller_id', $item['seller_id'])->get(); + $item['shippings'] = $shippings; + $item['selected_shipping_fee'] = $shippings->isNotEmpty() ? $shippings->first()->shipping_fee : 0; + $cartItems[$id] = $item; + } + + // Retrieve the authenticated user's delivery addresses (fixing empty result) + $addresses = Auth::user()->deliveryAddresses ?? collect([]); + \Log::debug('Cart items:', ['data' => $cartItems]); // <-- debugging log + \Log::debug('User addresses:', ['data' => $addresses->toArray()]); // <-- debugging log + + return view('cart.index', compact('cartItems', 'addresses')); } public function add(Request $request) @@ -34,10 +51,12 @@ public function add(Request $request) 'category' => $product->category, 'quantity' => $request->quantity, 'image' => $productThumbnail, + 'seller_id'=> $product->seller_id, // <-- added seller_id ]; } Session::put('cart', $cart); + Log::debug('Cart updated after add:', $cart); // <-- debugging log if ($request->ajax()) { return view('partials.cart-items', compact('cart')); @@ -49,8 +68,10 @@ public function add(Request $request) public function checkout(Request $request) { $cart = Session::get('cart', []); + Log::debug('Checkout initiated. Cart:', $cart); // <-- debugging log if (empty($cart)) { + Log::debug('Cart is empty during checkout.'); return redirect()->back()->with('error', 'Your cart is empty!'); } @@ -60,11 +81,11 @@ public function checkout(Request $request) $product = Product::findOrFail($id); $groupedItems[$product->seller_id][] = $item; } + Log::debug('Grouped cart items by seller:', $groupedItems); // <-- debugging log // Create orders for each seller foreach ($groupedItems as $sellerId => $items) { $total = array_sum(array_map(fn($item) => $item['price'] * $item['quantity'], $items)); - Order::create([ 'buyer_id' => Auth::id(), 'seller_id' => $sellerId, @@ -73,10 +94,12 @@ public function checkout(Request $request) 'payment_method' => 'qr', 'status' => 'Pending', ]); + Log::debug("Order created for seller_id: {$sellerId} with total: {$total}", $items); } // Clear the cart Session::forget('cart'); + Log::debug('Cart cleared after checkout.'); return redirect()->back()->with('success', 'Order placed successfully!'); } @@ -84,12 +107,11 @@ public function checkout(Request $request) public function remove($id) { $cart = Session::get('cart', []); - if (isset($cart[$id])) { unset($cart[$id]); Session::put('cart', $cart); + Log::debug("Item {$id} removed from cart.", $cart); // <-- debugging log } - return redirect()->back()->with('success', 'Item removed from cart.'); } } diff --git a/resources/views/cart/index.blade.php b/resources/views/cart/index.blade.php index d975e17..d00f00c 100644 --- a/resources/views/cart/index.blade.php +++ b/resources/views/cart/index.blade.php @@ -1,40 +1,86 @@ +

    Shopping Cart

    + +
    + @if($addresses->isEmpty()) +
    + Warning: You have no delivery addresses. Please add one. +
    + @endif +
    + + +
    +
    - @if (empty($cart)) + @if (empty($cartItems))

    Your cart is empty.

    @else
    - @foreach ($cart as $id => $item) + @foreach ($cartItems as $id => $item)
    +
    +
    + @csrf + @method('DELETE') + +
    +
    - {{ $item['name'] }} + {{ $item['name'] }}
    + - + + + - + {{-- Shipping dropdown updated with data attributes --}} + @if($item['shippings']->isNotEmpty()) +
    + +
    + @endif
    @@ -79,6 +126,16 @@ class="inline-flex items-center text-sm font-medium text-red-600 hover:underline @endif
    + @php + $productsTotal = array_sum(array_map(fn($item) => $item['price'] * $item['quantity'], $cartItems)); + $shippingTotal = array_sum(array_map(fn($item) => $item['selected_shipping_fee'] * $item['quantity'], + $cartItems)); + $grandTotal = $productsTotal + $shippingTotal; + @endphp + + + +
    Total Items
    -
    {{ count($cart) }} +
    {{ count($cartItems) + }}
    -
    Total
    -
    - ${{ array_sum(array_map(fn($item) => $item['price'] * $item['quantity'], $cart)) - }} +
    Products Total +
    +
    + ${{ number_format($productsTotal, 2) }} +
    +
    + +
    +
    Shipping Total +
    +
    + ${{ number_format($shippingTotal, 2) }} +
    +
    + +
    +
    Grand Total
    +
    + ${{ number_format($grandTotal, 2) }}
    -
    + + + @csrf + class="{{ $addresses->isEmpty() ? 'hover:cursor-not-allowed text-white bg-blue-400 dark:bg-blue-500 font-medium rounded-lg text-sm px-5 py-2.5 text-center' : 'hover:cursor-pointer text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800' }} w-full" + @if($addresses->isEmpty()) disabled @endif> + Proceed to Checkout +
    + + + + +
    \ No newline at end of file From cb2ad5f714d04b8e078c6fc56599d96c6072fc6c Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Thu, 1 May 2025 02:50:37 +0800 Subject: [PATCH 142/298] modification migration for shippings table --- ...174519_add_column_into_shippings_table.php | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 database/migrations/2025_04_30_174519_add_column_into_shippings_table.php diff --git a/database/migrations/2025_04_30_174519_add_column_into_shippings_table.php b/database/migrations/2025_04_30_174519_add_column_into_shippings_table.php new file mode 100644 index 0000000..48f13b7 --- /dev/null +++ b/database/migrations/2025_04_30_174519_add_column_into_shippings_table.php @@ -0,0 +1,29 @@ +unsignedBigInteger('seller_id')->after('id'); + $table->foreign('seller_id')->references('id')->on('users')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('shippings', function (Blueprint $table) { + // + }); + } +}; From bb03263d54e0471dc525569026a7cd5b6a9e2f6f Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Thu, 1 May 2025 23:19:00 +0800 Subject: [PATCH 143/298] Refactor admin controllers and views to enhance order, rating, and transaction management - Updated ListOrderController to fetch and display all orders in the admin view. - Modified RatingController to retrieve and display all reviews for products. - Adjusted TransactionController to fetch all orders instead of only paid ones. - Enhanced AdminController to aggregate data for users, orders, products, reviews, and transactions for the dashboard. - Updated orders migration to set default statuses to 'pending'. - Improved admin dashboard view with charts for transactions and order statuses, and added detailed reviews section. - Enhanced orders view to display order details including buyer, seller, items, total, and statuses. - Updated ratings view to display customer reviews with detailed information. - Refined transactions view to focus on order details without redundant status columns. - Adjusted cart view to display prices in RM instead of $. - Updated sidebar navigation to include relevant admin routes. - Enhanced customer layout to conditionally display account links based on user roles. - Fixed avatar display in seller reviews view. --- .../Controllers/Admin/ListOrderController.php | 4 +- .../Controllers/Admin/RatingController.php | 5 +- .../Admin/TransactionController.php | 3 +- app/Http/Controllers/AdminController.php | 49 +- .../2025_04_19_153612_create_orders_table.php | 4 +- resources/views/admin/dashboard.blade.php | 568 +++++++++++------- resources/views/admin/orders.blade.php | 48 +- resources/views/admin/ratings.blade.php | 50 +- resources/views/admin/transactions.blade.php | 22 +- resources/views/cart/index.blade.php | 6 +- .../components/layouts/app/sidebar.blade.php | 6 +- .../layouts/customer-layout.blade.php | 33 +- resources/views/seller/reviews.blade.php | 2 +- 13 files changed, 539 insertions(+), 261 deletions(-) diff --git a/app/Http/Controllers/Admin/ListOrderController.php b/app/Http/Controllers/Admin/ListOrderController.php index bf94fc0..1c2867c 100644 --- a/app/Http/Controllers/Admin/ListOrderController.php +++ b/app/Http/Controllers/Admin/ListOrderController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; +use App\Models\Order; use Illuminate\Http\Request; class ListOrderController extends Controller @@ -13,7 +14,8 @@ class ListOrderController extends Controller public function index() { // - return view('admin.orders'); + $orders = Order::all(); + return view('admin.orders',compact('orders')); } /** diff --git a/app/Http/Controllers/Admin/RatingController.php b/app/Http/Controllers/Admin/RatingController.php index bd97dc8..a086b8f 100644 --- a/app/Http/Controllers/Admin/RatingController.php +++ b/app/Http/Controllers/Admin/RatingController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; +use App\Models\Review; use Illuminate\Http\Request; class RatingController extends Controller @@ -13,7 +14,9 @@ class RatingController extends Controller public function index() { // - return view('admin.ratings'); + // Retrieve reviews for products that belong to the seller + $reviews = Review::all(); + return view('admin.ratings',compact('reviews')); } /** diff --git a/app/Http/Controllers/Admin/TransactionController.php b/app/Http/Controllers/Admin/TransactionController.php index 11d35fe..212ac4a 100644 --- a/app/Http/Controllers/Admin/TransactionController.php +++ b/app/Http/Controllers/Admin/TransactionController.php @@ -14,8 +14,7 @@ class TransactionController extends Controller public function index() { // - Order::where('payment_status', 'paid')->get(); - $orders = Order::where('payment_status', 'paid')->get(); + $orders = Order::all(); return view('admin.transactions', compact('orders')); } diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index e4f6417..f35f3f7 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -2,6 +2,9 @@ namespace App\Http\Controllers; +use App\Models\Order; +use App\Models\Product; +use App\Models\Review; use App\Models\User; use Illuminate\Http\Request; use Spatie\Permission\Models\Role; @@ -14,8 +17,52 @@ class AdminController extends Controller public function index() { // + $users = User::all(); + $orders = Order::all(); + $products = Product::all(); + $reviews = Review::all(); - return view('admin.dashboard'); + $sellers = User::role('seller')->get(); // Fetch all sellers + $buyers = User::role('buyer')->get(); // Fetch all buyers + $admins = User::role('admin')->get(); // Fetch all admins + + $buyersCount = $buyers->count(); + $sellersCount = $sellers->count(); + + // Group transactions by day and count them + $transactions = Order::selectRaw('DATE(created_at) as date, COUNT(*) as count') + ->groupBy('date') + ->orderBy('date', 'ASC') + ->get(); + + // Prepare data for the chart + $transactionDates = $transactions->pluck('date')->map(function ($date) { + return \Carbon\Carbon::parse($date)->format('d F'); // Format date as '01 February' + }); + $transactionCounts = $transactions->pluck('count'); + + // Calculate order statuses + $pendingOrders = Order::where('payment_status', 'pending')->count(); + $paidOrders = Order::where('payment_status', 'paid')->count(); + $cancelledOrders = Order::where('payment_status', 'cancelled')->count(); + + + return view('admin.dashboard',compact( + 'users', + 'orders', + 'products', + 'reviews', + 'sellers', + 'buyers', + 'admins', + 'buyersCount', + 'sellersCount', + 'transactionDates', + 'transactionCounts', + 'pendingOrders', + 'paidOrders', + 'cancelledOrders' + )); } /** diff --git a/database/migrations/2025_04_19_153612_create_orders_table.php b/database/migrations/2025_04_19_153612_create_orders_table.php index ae12947..4f6f38f 100644 --- a/database/migrations/2025_04_19_153612_create_orders_table.php +++ b/database/migrations/2025_04_19_153612_create_orders_table.php @@ -17,8 +17,8 @@ public function up(): void $table->foreignId('seller_id')->constrained('users')->onDelete('cascade'); $table->json('items'); // Store cart items as JSON $table->decimal('total', 10, 2); - $table->string('delivery_status')->default('Pending'); // e.g., Pending, Completed - $table->string('payment_status')->default('Pending'); // e.g., Pending, Completed + $table->string('delivery_status')->default('pending'); // e.g., Pending, Completed + $table->string('payment_status')->default('pending'); // e.g., Pending, Completed $table->string('payment_method'); // e.g., Pending, Completed $table->timestamps(); }); diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php index 3538f80..0a027f5 100644 --- a/resources/views/admin/dashboard.blade.php +++ b/resources/views/admin/dashboard.blade.php @@ -1,218 +1,362 @@ Admin Dashboard - - {{-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - Company Name - - - - Ticker - - - - Stock Price - - - - Market Capitalization - -
    Apple Inc.AAPL$192.58$3.04T
    Microsoft CorporationMSFT$340.54$2.56T
    Alphabet Inc.GOOGL$134.12$1.72T
    Amazon.com Inc.AMZN$138.01$1.42T
    NVIDIA CorporationNVDA$466.19$1.16T
    Tesla Inc.TSLA$255.98$811.00B
    Meta Platforms Inc.META$311.71$816.00B
    Berkshire Hathaway Inc.BRK.B$354.08$783.00B
    TSMCTSM$103.51$538.00B
    UnitedHealth Group Incorporated - UNH$501.96$466.00B
    Johnson & JohnsonJNJ$172.85$452.00B
    JPMorgan Chase & Co.JPM$150.23$431.00B
    Visa Inc.V$246.39$519.00B
    Eli Lilly and CompanyLLY$582.97$552.00B
    Walmart Inc.WMT$159.67$429.00B
    Samsung Electronics Co., Ltd. - 005930.KS$70.22$429.00B
    Procter & Gamble Co.PG$156.47$366.00B
    Nestlé S.A.NESN.SW$120.51$338.00B
    Roche Holding AGROG.SW$296.00$317.00B
    Chevron CorporationCVX$160.92$310.00B
    LVMH Moët Hennessy Louis Vuitton - MC.PA$956.60$478.00B
    Pfizer Inc.PFE$35.95$200.00B
    Novo Nordisk A/SNVO$189.15$443.00B
    PepsiCo, Inc.PEP$182.56$311.00B
    ASML Holding N.V.ASML$665.72$273.00B
    The Coca-Cola CompanyKO$61.37$265.00B
    Oracle CorporationORCL$118.36$319.00B
    Merck & Co., Inc.MRK$109.12$276.00B
    Broadcom Inc.AVGO$861.80$356.00B
    Mastercard IncorporatedMA$421.44$396.00B
    --}} +
    + +
    + +
    + +
    +
    +

    Total Users

    +

    {{ $users->count() }}

    +
    +
    +

    Total Products

    +

    {{ $products->count() }}

    +
    +
    +

    Total Orders

    +

    {{ $orders->count() }}

    +
    +
    +
    +
    +

    Sellers & Buyers

    +
    +
    +
    +

    Transactions

    +
    +
    +
    +

    Rating & Reviews

    + + + + + + + + + + @foreach ($reviews as $review) + + + + + + @endforeach +
    + User + + Product + + Rating +
    + Rounded avatar{{ $review->user->name }} + + {{ $review->product->name }} + + @for ($i = 0; $i < $review->rating; $i++) + + @endfor +
    + +
    +
    +
    + +
    + +
    +
    + + + + + + +
    \ No newline at end of file diff --git a/resources/views/admin/orders.blade.php b/resources/views/admin/orders.blade.php index 47cbff3..bfc64df 100644 --- a/resources/views/admin/orders.blade.php +++ b/resources/views/admin/orders.blade.php @@ -1,7 +1,53 @@ List Of Orders - +
    +
    + + + + + + + + + + + + + + @foreach ($orders as $order) + + + + + + + + + + + @endforeach + +
    Order IDBuyerSellerItemsTotalPayment StatusDelivery Status
    {{ $order->id }}{{ $order->buyer->name ?? 'N/A' }}{{ $order->seller->name ?? 'N/A' }} +
      + @foreach ($order->items as $item) +
    • {{ $item['name'] }} (x{{ $item['quantity'] }})
    • + @endforeach +
    +
    RM{{ number_format($order->total, 2) }} + + {{ ucfirst($order->payment_status) }} + + + + {{ ucfirst($order->delivery_status) }} + +
    +
    +
    diff --git a/resources/views/admin/ratings.blade.php b/resources/views/admin/ratings.blade.php index d38c8d5..83e80c2 100644 --- a/resources/views/admin/ratings.blade.php +++ b/resources/views/admin/ratings.blade.php @@ -1,7 +1,55 @@ Rating & Reviews - + @if (session('success')) + + @endif + + @if ($errors->any()) + + @endif +
    +

    Customer Reviews

    + + + + + + + + + + + + + + @foreach ($reviews as $review) + + + + + + + + + + + @endforeach + +
    ProductCustomerReviewCommentRatingResponseDate
    {{ $review->product->name }} + Customer Avatar + {{ $review->user->name }} + {{ $review->title }}{{ $review->content }}{{ $review->rating }} / 5{{ $review->response ?? 'No Response' }}{{ $review->created_at->format('Y-m-d') }}
    +
    diff --git a/resources/views/admin/transactions.blade.php b/resources/views/admin/transactions.blade.php index d97df2a..55f97bd 100644 --- a/resources/views/admin/transactions.blade.php +++ b/resources/views/admin/transactions.blade.php @@ -11,9 +11,7 @@
    Seller Items TotalPayment StatusDelivery StatusActions
    RM{{ number_format($order->total, 2) }} - - {{ ucfirst($order->payment_status) }} - - - - {{ ucfirst($order->delivery_status) }} - - - View - + View +
    {{ $review->product->name }} - Customer Avatar + Customer Avatar {{ $review->user->name }} {{ $review->title }}
    + + + + + + + + + + @foreach($order->items['cart_items'] as $item) + + + + + + + @endforeach + +
    ProductQuantityUnit PriceSubtotal
    {{ $item['name'] ?? 'Item' }}{{ $item['quantity'] }}RM{{ number_format($item['price'], 2) }}RM{{ number_format($item['price'] * $item['quantity'], 2) }}
    + + +
    +

    + Total: RM{{ number_format($order->total, 2) }} +

    +
    + + + + \ No newline at end of file From af319d249683d4441d2fe6f6097ce287c0ba56cd Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Sat, 3 May 2025 02:31:40 +0800 Subject: [PATCH 154/298] update order listy --- resources/views/buyer/account-profile.blade.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/views/buyer/account-profile.blade.php b/resources/views/buyer/account-profile.blade.php index fd90d68..9b57527 100644 --- a/resources/views/buyer/account-profile.blade.php +++ b/resources/views/buyer/account-profile.blade.php @@ -19,7 +19,7 @@ -
    +
    @@ -213,8 +213,8 @@ class="text-xs font-normal text-gray-500 dark:text-gray-300">

    No orders found.

    @else @foreach ($latestOrders as $order) - id" :date="$order->created_at->format('d.m.Y')" :price="$order->total" :payment_method="$order->payment_method" :delivery_address="$order->delivery_address" :status="$order->status" :productName="$order->product_name" :productImage="$order->product_image" :quantity="$order->quantity" + :delivery_status="$order->delivery_status" :payment_status="$order->payment_status" :actions="[ ['url' => '#', 'label' => 'Order again', 'icon' => ''], ['url' => '#', 'label' => 'Order details', 'icon' => ''], ['url' => '#', 'label' => 'Cancel order', 'icon' => '', 'class' => 'text-red-600 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white'] From be87928aead2f8046fa47978aa8d20752a9c0a1a Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Sat, 3 May 2025 02:31:47 +0800 Subject: [PATCH 155/298] update order list --- .../views/components/order-list.blade.php | 72 ++++++++++++------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/resources/views/components/order-list.blade.php b/resources/views/components/order-list.blade.php index 5fa8bbb..e279309 100644 --- a/resources/views/components/order-list.blade.php +++ b/resources/views/components/order-list.blade.php @@ -1,10 +1,10 @@ -@props(['orderId', 'date', 'price', 'status', 'actions' => []]) +@props(['orderId', 'date', 'price', 'delivery_status', 'payment_status', 'payment_method', 'actions' => []])
    Order ID:
    - {{ $orderId }} + {{ $orderId }}
    @@ -15,43 +15,67 @@
    Price:
    -
    ${{ number_format($price, 2) }}
    +
    {{ (number_format($price, 2)) }}
    +
    + +
    +
    Payment Method:
    +
    {{ ($payment_method == 'online_banking' ? 'Online Banking' : 'QR Payment') }}
    +
    + +
    +
    Delivery Status:
    +
    + + {{ $delivery_status }} +
    -
    Status:
    +
    Payment Status:
    -
    {{--
    - - - `
    + + \ No newline at end of file From 5c8177e982e0632168a54ed753a5ed233d61ea9c Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 7 May 2025 02:47:48 +0800 Subject: [PATCH 181/298] add receipt column and display functionality to orders table --- resources/views/seller/orders.blade.php | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/resources/views/seller/orders.blade.php b/resources/views/seller/orders.blade.php index 932a05b..8536054 100644 --- a/resources/views/seller/orders.blade.php +++ b/resources/views/seller/orders.blade.php @@ -69,6 +69,11 @@ + + + Receipt + + @@ -81,11 +86,13 @@ class="font-medium text-gray-900 whitespace-nowrap dark:text-white"> @push('modal') @@ -104,7 +111,7 @@ class="absolute invisible inline-block px-3 py-2 text-sm font-medium text-white {{ $order->buyer->id }} {{ $order->created_at->format('Y-m-d') }} RM{{ number_format($order->total, 2) }} - {{ $order->payment_method }} + {{ $order->payment_method === 'cod' ? 'Cash On Delivery' : 'Online Banking' }} + + + @if ($order->file_receipt) + + + + @else + No Receipt + @endif + @endforeach From a0b4160cec0d71162f7f27d3867309d2867a25f9 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 7 May 2025 02:47:59 +0800 Subject: [PATCH 182/298] fix: remove redundant border class from reviews table --- resources/views/seller/reviews.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/seller/reviews.blade.php b/resources/views/seller/reviews.blade.php index 04278dd..a8649ae 100644 --- a/resources/views/seller/reviews.blade.php +++ b/resources/views/seller/reviews.blade.php @@ -18,7 +18,7 @@ @endif

    Customer Reviews

    - +
    From 8226aa09f48853644db4bf343e184364789cf0cc Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 7 May 2025 02:53:02 +0800 Subject: [PATCH 183/298] kasi nampak button add review ni, kita bg bg color --- resources/views/components/review-progress-bar.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/components/review-progress-bar.blade.php b/resources/views/components/review-progress-bar.blade.php index 52ed99b..46f6bc9 100644 --- a/resources/views/components/review-progress-bar.blade.php +++ b/resources/views/components/review-progress-bar.blade.php @@ -7,7 +7,7 @@ {{ $averageRating }} out of 5

    From cb79215e3772a3873c4732897310fe2f137d7663 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 7 May 2025 03:11:35 +0800 Subject: [PATCH 184/298] display invoice details --- app/Http/Controllers/BuyerController.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/BuyerController.php b/app/Http/Controllers/BuyerController.php index eebf8ba..96c963d 100644 --- a/app/Http/Controllers/BuyerController.php +++ b/app/Http/Controllers/BuyerController.php @@ -663,6 +663,14 @@ public function showInvoice(\App\Models\Order $order) if (auth()->id() !== $order->buyer_id) { abort(403, 'Unauthorized access to invoice.'); } - return view('invoice', compact('order')); + + // Decode the JSON-encoded items + $decodedItems = json_decode($order->items, true); // Decode as an associative array + + // Access the 'cart_items' key + $decodedOrder = $decodedItems['cart_items'] ?? []; + $shipping_total = $decodedItems['shipping_total']; + + return view('invoice', compact('decodedOrder','order','shipping_total')); } } From 719b16b25de0e5c27518c0f4ad1109fd201c8925 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 7 May 2025 03:12:27 +0800 Subject: [PATCH 185/298] display shipping fee --- resources/views/invoice.blade.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/views/invoice.blade.php b/resources/views/invoice.blade.php index efde748..9256bb1 100644 --- a/resources/views/invoice.blade.php +++ b/resources/views/invoice.blade.php @@ -47,6 +47,7 @@ class="px-2.5 py-0.5 text-xs font-medium mx-1 mt-1.5 inline-flex shrink-0 items-
  • Seller: {{ $order->seller->name ?? 'Seller' }}
  • Payment: {{ ($order->payment_method == 'online_banking' ? 'Online Banking' : 'QR Payment') }}
  • +
  • Shipping Fee: RM{{ number_format($shipping_total, 2) }}
  • Total: RM{{ number_format($order->total, 2) }}
  • @@ -64,7 +65,7 @@ class="px-2.5 py-0.5 text-xs font-medium mx-1 mt-1.5 inline-flex shrink-0 items-
    - @foreach($order->items['cart_items'] as $item) + @foreach($decodedOrder as $item) From e047ca521f07c0e9aff6dfe8cbaf5717a1cbd591 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 7 May 2025 03:13:21 +0800 Subject: [PATCH 186/298] no qr --- resources/views/invoice.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/invoice.blade.php b/resources/views/invoice.blade.php index 9256bb1..6e967d4 100644 --- a/resources/views/invoice.blade.php +++ b/resources/views/invoice.blade.php @@ -46,7 +46,7 @@ class="px-2.5 py-0.5 text-xs font-medium mx-1 mt-1.5 inline-flex shrink-0 items-
  • Buyer: {{ $order->buyer->name ?? 'Guest' }}
  • Seller: {{ $order->seller->name ?? 'Seller' }}
  • Payment: {{ ($order->payment_method == - 'online_banking' ? 'Online Banking' : 'QR Payment') }}
  • + 'online_banking' ? 'Online Banking' : 'Cash On Delivery') }}
  • Shipping Fee: RM{{ number_format($shipping_total, 2) }}
  • Total: RM{{ number_format($order->total, 2) }}
  • From 1ab55f97d0c058fb37f6de55fd71ccc99889cb83 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 7 May 2025 03:15:17 +0800 Subject: [PATCH 187/298] logic error --- resources/views/invoice.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/invoice.blade.php b/resources/views/invoice.blade.php index 6e967d4..546e6a6 100644 --- a/resources/views/invoice.blade.php +++ b/resources/views/invoice.blade.php @@ -26,8 +26,8 @@
  • Payment Status: - {{ $order->delivery_status }} + {{ $order->payment_status == 'paid' ? 'bg-green-100 text-green-800' : ($order->payment_status == 'pending' ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800') }}"> + {{ $order->payment_status }}
  • Delivery Status: From 469a269c0798d4761c4f0837bceeb896f91ae675 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 7 May 2025 03:16:07 +0800 Subject: [PATCH 188/298] lol --- resources/views/invoice.blade.php | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/resources/views/invoice.blade.php b/resources/views/invoice.blade.php index 546e6a6..9ffa5bd 100644 --- a/resources/views/invoice.blade.php +++ b/resources/views/invoice.blade.php @@ -1,20 +1,23 @@
    - - + + -
    -

    Invoice

    -

    Order Summary & Payment Details

    -
    +
    +

    Invoice

    +

    Order Summary & Payment Details

    +
    @@ -47,7 +50,7 @@ class="px-2.5 py-0.5 text-xs font-medium mx-1 mt-1.5 inline-flex shrink-0 items-
  • Seller: {{ $order->seller->name ?? 'Seller' }}
  • Payment: {{ ($order->payment_method == 'online_banking' ? 'Online Banking' : 'Cash On Delivery') }}
  • -
  • Shipping Fee: RM{{ number_format($shipping_total, 2) }}
  • +
  • Shipping Fee: RM{{ number_format($shipping_total, 2)}}
  • Total: RM{{ number_format($order->total, 2) }}
  • From 24d03030372ae030c23f1da5c4014b3643abf5a8 Mon Sep 17 00:00:00 2001 From: Nasrulhaq Hidayat Abdul Latiff Date: Wed, 7 May 2025 03:34:15 +0800 Subject: [PATCH 189/298] asds --- app/Http/Controllers/Buyer/CartController.php | 184 +++++++++--------- 1 file changed, 97 insertions(+), 87 deletions(-) diff --git a/app/Http/Controllers/Buyer/CartController.php b/app/Http/Controllers/Buyer/CartController.php index 442db12..ff223cd 100644 --- a/app/Http/Controllers/Buyer/CartController.php +++ b/app/Http/Controllers/Buyer/CartController.php @@ -19,7 +19,7 @@ class CartController extends Controller public function index() { $cart = Session::get('cart', []); - + // Prepare cart items with shipping options and default shipping fee $cartItems = []; foreach ($cart as $id => $item) { @@ -28,12 +28,12 @@ public function index() $item['selected_shipping_fee'] = $shippings->isNotEmpty() ? $shippings->first()->shipping_fee : 0; $cartItems[$id] = $item; } - + // Retrieve the authenticated user's delivery addresses (fixing empty result) $addresses = Auth::user()->deliveryAddresses ?? collect([]); - \Log::debug('Cart items:', ['data' => $cartItems]); // <-- debugging log - \Log::debug('User addresses:', ['data' => $addresses->toArray()]); // <-- debugging log - + Log::debug('Cart items:', ['data' => $cartItems]); // <-- debugging log + Log::debug('User addresses:', ['data' => $addresses->toArray()]); // <-- debugging log + return view('cart.index', compact('cartItems', 'addresses')); } @@ -52,7 +52,7 @@ public function add(Request $request) 'category' => $product->category, 'quantity' => $request->quantity, 'image' => $productThumbnail, - 'seller_id'=> $product->seller_id, // <-- added seller_id + 'seller_id' => $product->seller_id, // <-- added seller_id ]; } @@ -68,103 +68,113 @@ public function add(Request $request) public function checkout(Request $request) { - try{ + try { $cart = Session::get('cart', []); - Log::debug('Checkout initiated. Cart:', $cart); + Log::debug('Checkout initiated. Cart:', $cart); - if (empty($cart)) { - Log::debug('Cart is empty during checkout.'); - return redirect()->back()->with('error', 'Your cart is empty!'); - } - // Validate the file receipt if payment method is not COD - $validatedData = $request->validate([ - 'file_receipt' => $request->input('payment_method') !== 'cod' ? 'required|mimes:jpg,jpeg,png,pdf|max:10240' : 'nullable', - ]); + if (empty($cart)) { + Log::debug('Cart is empty during checkout.'); + return redirect()->back()->with('error', 'Your cart is empty!'); + } - $fileReceiptPath = null; + // Validate the file receipt if payment method is not COD + $validatedData = $request->validate([ + 'file_receipt' => $request->input('payment_method') !== 'cod' ? 'required|mimes:jpg,jpeg,png,pdf|max:10240' : 'nullable', + ]); - // Handle file upload - if ($request->hasFile('file_receipt')) { - $fileReceiptPath = $request->file('file_receipt')->store('receipts', 'public'); - Log::debug('File receipt uploaded:', ['path' => $fileReceiptPath]); - } + $fileReceiptPath = null; - // Update cart quantities from JSON input (hidden inputs) - if ($request->has('cart')) { - $updated = $request->input('cart'); - foreach ($updated as $id => $data) { - if (isset($cart[$id])) { - $cart[$id]['quantity'] = (int)$data['quantity']; - } + // Handle file upload + if ($request->hasFile('file_receipt')) { + $fileReceiptPath = $request->file('file_receipt')->store('receipts', 'public'); + Log::debug('File receipt uploaded:', ['path' => $fileReceiptPath]); } - Session::put('cart', $cart); - Log::debug('Updated cart with new quantities:', $cart); - } - - // Retrieve shipping selections: shipping[product_id] => shipping option id - $shippingSelected = $request->input('shipping', []); - // Group items by seller - $groupedItems = []; - foreach ($cart as $id => $item) { - $product = Product::findOrFail($id); - $groupedItems[$product->seller_id][$id] = $item; - } - Log::debug('Grouped cart items by seller:', $groupedItems); - - // Create orders for each seller using recalculated totals including shipping fees. - foreach ($groupedItems as $sellerId => $items) { - $productSubtotal = 0; - $shippingTotal = 0; - // Loop each item by reference to attach shipping_id - foreach ($items as $id => &$item) { - $productSubtotal += $item['price'] * $item['quantity']; - if (isset($shippingSelected[$id])) { - $item['shipping_id'] = $shippingSelected[$id]; - $shippingOption = Shipping::find($shippingSelected[$id]); - if ($shippingOption) { - $shippingTotal += $shippingOption->shipping_fee * $item['quantity']; + // Update cart quantities from JSON input (hidden inputs) + if ($request->has('cart')) { + $updated = $request->input('cart'); + foreach ($updated as $id => $data) { + if (isset($cart[$id])) { + $cart[$id]['quantity'] = (int)$data['quantity']; } - } else { - $item['shipping_id'] = null; } + Session::put('cart', $cart); + Log::debug('Updated cart with new quantities:', $cart); } - unset($item); // Break reference - $grandTotal = $productSubtotal + $shippingTotal; + // Retrieve shipping selections: shipping[product_id] => shipping option id + $shippingSelected = $request->input('shipping', []); - $orderItems = [ - 'delivery_address_id' => $request->input('delivery_address'), - 'cart_items' => $items, - 'shipping_total' => $shippingTotal, - ]; + // Group items by seller + $groupedItems = []; + foreach ($cart as $id => $item) { + $product = Product::findOrFail($id); + $groupedItems[$product->seller_id][$id] = $item; + } + Log::debug('Grouped cart items by seller:', $groupedItems); + + // Create orders for each seller using recalculated totals including shipping fees. + foreach ($groupedItems as $sellerId => $items) { + $productSubtotal = 0; + $shippingTotal = 0; + + foreach ($items as $id => &$item) { + $productSubtotal += $item['price'] * $item['quantity']; + if (isset($shippingSelected[$id])) { + $item['shipping_id'] = $shippingSelected[$id]; + $shippingOption = Shipping::find($shippingSelected[$id]); + if ($shippingOption) { + $shippingTotal += $shippingOption->shipping_fee * $item['quantity']; + } + } else { + $item['shipping_id'] = null; + } - // Encode $orderItems as JSON - $orderItemsJson = json_encode($orderItems); - - Order::create([ - 'buyer_id' => Auth::id(), - 'seller_id' => $sellerId, - 'items' => $orderItemsJson, - 'total' => $grandTotal, - 'payment_method' => $request->input('payment_method', 'qr'), - 'payment_status' => $request->input('payment_method') === 'cod' ? 'pending' : 'paid', // Dynamically set status - 'file_receipt' => $fileReceiptPath, // Save the file receipt path - ]); - Log::debug("file send: {$sellerId} : {$fileReceiptPath}"); - Log::debug("Order created for seller_id: {$sellerId} with grand total: {$grandTotal}", $items); - } + // Reduce stock for the product + $product = Product::findOrFail($id); + if ($product->stock >= $item['quantity']) { + $product->stock -= $item['quantity']; + $product->save(); + Log::debug("Stock reduced for product ID {$id}. Remaining stock: {$product->stock}"); + } else { + Log::debug("Insufficient stock for product ID {$id}. Requested: {$item['quantity']}, Available: {$product->stock}"); + return redirect()->back()->with('error', "Insufficient stock for product: {$product->name}"); + } + } + unset($item); // Break reference + + $grandTotal = $productSubtotal + $shippingTotal; + + $orderItems = [ + 'delivery_address_id' => $request->input('delivery_address'), + 'cart_items' => $items, + 'shipping_total' => $shippingTotal, + ]; + + // Encode $orderItems as JSON + $orderItemsJson = json_encode($orderItems); + + Order::create([ + 'buyer_id' => Auth::id(), + 'seller_id' => $sellerId, + 'items' => $orderItemsJson, + 'total' => $grandTotal, + 'payment_method' => $request->input('payment_method', 'qr'), + 'payment_status' => $request->input('payment_method') === 'cod' ? 'pending' : 'paid', // Dynamically set status + 'file_receipt' => $fileReceiptPath, // Save the file receipt path + ]); + Log::debug("Order created for seller_id: {$sellerId} with grand total: {$grandTotal}", $items); + } - // Clear the cart - Session::forget('cart'); - Log::debug('Cart cleared after checkout.'); + // Clear the cart + Session::forget('cart'); + Log::debug('Cart cleared after checkout.'); - return redirect()->route('buyer.dashboard')->with('success', 'Order placed successfully!'); - }catch(Throwable $e){ - Log::debug('Somehing went wrong:: '.$e); - return redirect()->back()->with('error', 'Error occured: '.$e); + return redirect()->route('buyer.dashboard')->with('success', 'Order placed successfully!'); + } catch (Throwable $e) { + Log::debug('Something went wrong:: ' . $e); + return redirect()->back()->with('error', 'Error occurred: ' . $e->getMessage()); } - } public function remove($id) From 2b995e58d7ca0f9de620d02d84a98d503aebba14 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Wed, 7 May 2025 16:11:10 +0800 Subject: [PATCH 190/298] show products with stock >0 --- app/Http/Controllers/BuyerController.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/Http/Controllers/BuyerController.php b/app/Http/Controllers/BuyerController.php index 96c963d..024f222 100644 --- a/app/Http/Controllers/BuyerController.php +++ b/app/Http/Controllers/BuyerController.php @@ -58,6 +58,7 @@ public function index() elseif ($categoryFilter) { $products = Product::with('category') ->where('category_id', $categoryFilter) + ->where('stock', '>', 0) // Only show products with stock >0 ->latest() ->paginate(12); } @@ -65,6 +66,7 @@ public function index() else { if ($user) { $products = Product::with('category') + ->where('stock', '>', 0) // Only show products with stock >0 ->leftJoin('user_category_preferences', function ($join) use ($user) { $join->on('products.category_id', '=', 'user_category_preferences.category_id') ->where('user_category_preferences.user_id', $user->id); @@ -75,6 +77,7 @@ public function index() ->paginate(12); } else { $products = Product::with('category') + ->where('stock', '>', 0) // Only show products with stock >0 ->latest() ->paginate(12); } @@ -192,6 +195,7 @@ private function getProductsFromPreferredCategories($sortedCategories) // Get products from top categories $products = Product::with('category') ->whereIn('category_id', $categoryIds) + ->where('stock', '>', 0) // Only show products with stock >0 ->latest() ->take(50) // Get a good sample to work with ->get(); @@ -249,6 +253,7 @@ private function getCollaborativeRecommendations($user, $userPreferences) // Get products from these categories $products = Product::whereIn('category_id', array_keys($recommendedCategories)) + ->where('stock', '>', 0) // Only show products with stock >0 ->latest() ->take(20) ->get(); @@ -384,6 +389,7 @@ private function handleSearchAndUpdatePreferences($search, $user) // Get direct matches first - only search by name $directMatches = Product::with('category') ->where('name', 'like', '%' . $search . '%') + ->where('stock', '>', 0) // Only show products with stock >0 ->latest() ->get(); @@ -544,6 +550,7 @@ private function getRelatedProducts($product, $user = null) // 2. If user logged in, consider their preferences too $query = Product::where('id', '!=', $product->id) ->where('category_id', $product->category_id) + ->where('stock', '>', 0) // Only show products with stock >0 ->latest(); // If user is logged in and has preferences, boost products from their other preferred categories @@ -558,6 +565,7 @@ private function getRelatedProducts($product, $user = null) // Use union to combine with products from preferred categories $preferredQuery = Product::where('id', '!=', $product->id) ->whereIn('category_id', $preferredCategories) + ->where('stock', '>', 0) // Only show products with stock >0 ->latest() ->take(3); From ceebdf66fae079786a1c8e744c387b391fc1ff48 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Wed, 7 May 2025 16:55:34 +0800 Subject: [PATCH 191/298] better carousel buttons --- resources/views/product/product-view.blade.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/resources/views/product/product-view.blade.php b/resources/views/product/product-view.blade.php index 0e7c42e..f9ed8bc 100644 --- a/resources/views/product/product-view.blade.php +++ b/resources/views/product/product-view.blade.php @@ -11,8 +11,16 @@
    - - + + {{ $product->name }} From 308ec42cc80f92612a877b60461d96bdd17c96fb Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Wed, 7 May 2025 16:55:50 +0800 Subject: [PATCH 192/298] fix small main image focus --- resources/views/product/product-view.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/product/product-view.blade.php b/resources/views/product/product-view.blade.php index f9ed8bc..2ea6316 100644 --- a/resources/views/product/product-view.blade.php +++ b/resources/views/product/product-view.blade.php @@ -23,8 +23,8 @@ - {{ $product->name }} - + {{ $product->name }} +
    From 6e7e138661cf2282057925f43984ddf384450b04 Mon Sep 17 00:00:00 2001 From: Muhammad Zaim Date: Wed, 7 May 2025 16:57:26 +0800 Subject: [PATCH 193/298] quantity limit warning by checking the stock when attempting to add to cart --- resources/views/product/product-view.blade.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/resources/views/product/product-view.blade.php b/resources/views/product/product-view.blade.php index 2ea6316..9982d4e 100644 --- a/resources/views/product/product-view.blade.php +++ b/resources/views/product/product-view.blade.php @@ -99,6 +99,8 @@ class="ml-4 text-accent-content cursor-not-allowed dark:text-white bg-primary-7 @endrole
    + +
    @@ -191,6 +193,16 @@ function scrollThumbnailIntoView(index) { $('#thumbnailGrid img.thumb').eq(currentIndex).addClass('active'); scrollThumbnailIntoView(currentIndex); }); + + $('input[name="quantity"]').on('input', function(){ + var max = parseInt($(this).attr('max')); + var val = parseInt($(this).val()); + if(val >= max){ + $('#quantityMessage').removeClass('hidden').text("You have reached the maximum available stock (" + max + ")."); + } else { + $('#quantityMessage').addClass('hidden').text(""); + } + }); });
  • Product
    {{ $item['name'] ?? 'Item' }} {{ $item['quantity'] }}