├── .editorconfig ├── .example.env ├── .gitattributes ├── .gitignore ├── .styleci.yml ├── .vscode └── settings.json ├── LICENSE ├── Procfile ├── README.md ├── app ├── Category.php ├── Console │ ├── Commands │ │ ├── EcommerceInstall.php │ │ └── HerokuSetup.php │ └── Kernel.php ├── CountryVisit.php ├── Coupon.php ├── Exceptions │ └── Handler.php ├── Http │ ├── Controllers │ │ ├── Auth │ │ │ ├── ConfirmPasswordController.php │ │ │ ├── ForgotPasswordController.php │ │ │ ├── LoginController.php │ │ │ ├── RegisterController.php │ │ │ ├── ResetPasswordController.php │ │ │ └── VerificationController.php │ │ ├── CartController.php │ │ ├── CheckoutController.php │ │ ├── Controller.php │ │ ├── CouponsController.php │ │ ├── HomeController.php │ │ ├── ShopController.php │ │ ├── VisitsController.php │ │ ├── Voyager │ │ │ └── OrdersController.php │ │ └── WelcomePageController.php │ ├── Kernel.php │ ├── Middleware │ │ ├── AdminMiddleware.php │ │ ├── Authenticate.php │ │ ├── CheckForMaintenanceMode.php │ │ ├── EncryptCookies.php │ │ ├── RedirectIfAuthenticated.php │ │ ├── TrimStrings.php │ │ ├── TrustProxies.php │ │ ├── VerifyCsrfToken.php │ │ └── VisitsMiddleware.php │ └── Requests │ │ └── CheckoutRequest.php ├── Mail │ └── OrderPlaced.php ├── Order.php ├── OrderProduct.php ├── Product.php ├── ProductTag.php ├── Providers │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── BroadcastServiceProvider.php │ ├── EventServiceProvider.php │ └── RouteServiceProvider.php ├── Tag.php ├── User.php └── library │ └── helper.php ├── artisan ├── bootstrap ├── app.php └── cache │ └── .gitignore ├── composer.json ├── composer.lock ├── config ├── app.php ├── auth.php ├── broadcasting.php ├── cache.php ├── cart.php ├── database.php ├── filesystems.php ├── geoip.php ├── hashing.php ├── hooks.php ├── image.php ├── logging.php ├── mail.php ├── queue.php ├── scout.php ├── services.php ├── session.php ├── view.php ├── voyager-hooks.php └── voyager.php ├── database ├── .gitignore ├── factories │ └── UserFactory.php ├── migrations │ ├── 2014_10_12_000000_create_users_table.php │ ├── 2014_10_12_100000_create_password_resets_table.php │ ├── 2019_08_19_000000_create_failed_jobs_table.php │ ├── 2019_10_16_185424_create_products_table.php │ ├── 2019_10_17_195112_create_categories_table.php │ ├── 2019_10_17_195227_add_category_id_to_products_table.php │ ├── 2019_10_18_002421_create_coupons_table.php │ ├── 2019_10_19_145706_add_images_column_to_products.php │ ├── 2019_10_20_114921_create_tags_table.php │ ├── 2019_10_20_115306_create_products_tags_table.php │ ├── 2019_10_22_185425_create_orders_table.php │ ├── 2019_10_22_190613_create_order_product_table.php │ ├── 2019_11_09_002942_add_quantity_to_products_table.php │ └── 2020_06_27_012504_create_visits_table.php └── seeds │ ├── CategoriesTableSeeder.php │ ├── CategoryTableSeeder.php │ ├── CouponsTableSeeder.php │ ├── DataRowsTableSeeder.php │ ├── DataRowsTableSeederCustom.php │ ├── DataTypesTableSeeder.php │ ├── DataTypesTableSeederCustom.php │ ├── DatabaseSeeder.php │ ├── MenuItemsTableSeeder.php │ ├── MenuItemsTableSeederCustom.php │ ├── MenusTableSeeder.php │ ├── MenusTableSeederCustom.php │ ├── OrderProductTableSeeder.php │ ├── OrdersTableSeeder.php │ ├── PagesTableSeeder.php │ ├── PermissionRoleTableSeeder.php │ ├── PermissionRoleTableSeederCustom.php │ ├── PermissionsTableSeeder.php │ ├── PermissionsTableSeederCustom.php │ ├── PostsTableSeeder.php │ ├── ProductTagSeeder.php │ ├── ProductsTableSeeder.php │ ├── RolesTableSeeder.php │ ├── SettingsTableSeeder.php │ ├── SettingsTableSeederCustom.php │ ├── TagsTableSeeder.php │ ├── TranslationsTableSeeder.php │ ├── UsersTableSeeder.php │ ├── VoyagerDatabaseSeeder.php │ ├── VoyagerDatabaseSeederCustom.php │ └── VoyagerDummyDatabaseSeeder.php ├── hooks └── hooks.json ├── package-lock.json ├── package.json ├── phpunit.xml ├── public ├── .htaccess ├── css │ └── app.css ├── favicon.ico ├── fonts │ ├── themify.eot │ ├── themify.svg │ ├── themify.ttf │ ├── themify.woff │ └── vendor │ │ └── font-awesome │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 ├── images │ ├── cover.jpg │ ├── not-found.jpg │ ├── products │ │ └── dummy │ │ │ ├── image0.jpg │ │ │ ├── image1.jpg │ │ │ ├── image2.jpg │ │ │ ├── image3.jpg │ │ │ ├── image4.jpg │ │ │ └── image5.jpg │ └── users │ │ └── default.png ├── index.php ├── js │ └── app.js ├── mix-manifest.json ├── robots.txt └── storage ├── resources ├── js │ ├── app.js │ ├── bootstrap.js │ └── main.js ├── lang │ └── en │ │ ├── auth.php │ │ ├── pagination.php │ │ ├── passwords.php │ │ └── validation.php ├── sass │ ├── _cart.scss │ ├── _checkout.scss │ ├── _main.scss │ ├── _product.scss │ ├── _shop.scss │ ├── _variables.scss │ ├── _welcome.scss │ ├── aos.css │ ├── app.scss │ └── cover.jpg └── views │ ├── admin │ └── visits.blade.php │ ├── auth │ ├── login.blade.php │ ├── passwords │ │ ├── email.blade.php │ │ └── reset.blade.php │ ├── register.blade.php │ └── verify.blade.php │ ├── cart.blade.php │ ├── checkout.blade.php │ ├── emails │ └── orders │ │ └── placed.blade.php │ ├── errors │ ├── 401.blade.php │ ├── 403.blade.php │ ├── 404.blade.php │ ├── 419.blade.php │ ├── 429.blade.php │ ├── 500.blade.php │ ├── 503.blade.php │ ├── illustrated-layout.blade.php │ ├── layout.blade.php │ └── minimal.blade.php │ ├── home.blade.php │ ├── layouts │ └── app.blade.php │ ├── partials │ ├── errors.blade.php │ ├── footer.blade.php │ ├── head.blade.php │ ├── menu │ │ └── main.blade.php │ ├── might-like.blade.php │ ├── nav.blade.php │ └── session.blade.php │ ├── product.blade.php │ ├── search.blade.php │ ├── shop.blade.php │ ├── vendor │ └── voyager │ │ └── orders │ │ ├── browse.blade.php │ │ └── read.blade.php │ └── welcome.blade.php ├── routes ├── api.php ├── channels.php ├── console.php └── web.php ├── server.php ├── storage ├── app │ ├── .gitignore │ └── public │ │ ├── products │ │ ├── September2020 │ │ │ ├── 7bmQiRD5DOS6QZTrprlb.jpg │ │ │ ├── DKCbwzXCrbgRjlUJjlko.jpg │ │ │ ├── FHyZzRWZ0Ze0CAqiURkx.jpg │ │ │ ├── gMuKbTUCz2AW9OS2Gqv1.jpg │ │ │ ├── nx65t4W6tw17XFoPnfrb.jpg │ │ │ └── xWLnSwcwkH4r7yhDn00F.jpg │ │ └── dummy │ │ │ ├── image0.jpg │ │ │ ├── image1.jpg │ │ │ ├── image2.jpg │ │ │ ├── image3.jpg │ │ │ ├── image4.jpg │ │ │ └── image5.jpg │ │ └── users │ │ └── default.png ├── debugbar │ └── .gitignore ├── framework │ ├── .gitignore │ ├── cache │ │ ├── .gitignore │ │ └── data │ │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ ├── testing │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore ├── tests ├── CreatesApplication.php ├── Feature │ └── ExampleTest.php ├── TestCase.php └── Unit │ └── ExampleTest.php └── webpack.mix.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.example.env: -------------------------------------------------------------------------------- 1 | APP_NAME=Ecommerce 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost:8000 6 | 7 | LOG_CHANNEL=stack 8 | 9 | DB_CONNECTION=mysql 10 | DB_HOST=127.0.0.1 11 | DB_PORT=3306 12 | DB_DATABASE= 13 | DB_USERNAME= 14 | DB_PASSWORD= 15 | 16 | BROADCAST_DRIVER=log 17 | CACHE_DRIVER=file 18 | QUEUE_CONNECTION=sync 19 | SESSION_DRIVER=file 20 | SESSION_LIFETIME=120 21 | 22 | REDIS_HOST=127.0.0.1 23 | REDIS_PASSWORD=null 24 | REDIS_PORT=6379 25 | 26 | MAIL_DRIVER=smtp 27 | MAIL_HOST=smtp.mailtrap.io 28 | MAIL_PORT=2525 29 | MAIL_USERNAME= 30 | MAIL_PASSWORD= 31 | MAIL_ENCRYPTION=null 32 | 33 | AWS_ACCESS_KEY_ID= 34 | AWS_SECRET_ACCESS_KEY= 35 | AWS_DEFAULT_REGION=us-east-1 36 | AWS_BUCKET= 37 | 38 | PUSHER_APP_ID= 39 | PUSHER_APP_KEY= 40 | PUSHER_APP_SECRET= 41 | PUSHER_APP_CLUSTER=mt1 42 | 43 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 44 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 45 | 46 | VOYAGER_ADMIN_PASSWORD=password 47 | 48 | STRIPE_KEY= 49 | STRIPE_SECRET= 50 | 51 | MAIL_FROM_ADDRESS= 52 | MAIL_FROM_NAME= 53 | 54 | ALGOLIA_APP_ID= 55 | ALGOLIA_SECRET= 56 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | *.js linguist-vendored 5 | CHANGELOG.md export-ignore 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/hot 3 | /storage/*.key 4 | /vendor 5 | .env 6 | .env.backup 7 | .phpunit.result.cache 8 | Homestead.json 9 | Homestead.yaml 10 | npm-debug.log 11 | yarn-error.log 12 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | php: 2 | preset: laravel 3 | enabled: 4 | - alpha_ordered_imports 5 | disabled: 6 | - length_ordered_imports 7 | - unused_use 8 | finder: 9 | not-name: 10 | - index.php 11 | - server.php 12 | js: 13 | finder: 14 | not-name: 15 | - webpack.mix.js 16 | css: true 17 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Aloglia" 4 | ], 5 | "cSpell.ignoreWords": [ 6 | "aloglia" 7 | ] 8 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mohammed Omer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: vendor/bin/heroku-php-apache2 public/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ecommerce-laravel-fullstack 2 | 3 | # Link : http://vampireecommerce.herokuapp.com 4 | 5 | This repo is based on the [youtube series](https://www.youtube.com/playlist?list=PLEhEHUEU3x5oPTli631ZX9cxl6cU_sDaR) by [@drehimself](https://github.com/drehimself) 6 | 7 | ## Features 8 | 9 | - Fully functional E-commerce website front-end and back-end built from scratch. 10 | - Using laravel voyager as an admin panel for the site. 11 | - javascript, jquery, bootstrap and css for the front-end. 12 | - Intelligent searching mechanism for products. 13 | - Awesome Cart package that uses session. 14 | - An artisan command to seed the database with all neccessary dummy data, even for voyager tables (php artisan ecommerce:install). 15 | - Different user roles and privileges. 16 | - Categories, tags and price filtering for easier search for products. 17 | - And much more features. 18 | 19 | --- 20 | 21 | ## Installation Guide 22 | 23 | 1. clone this repo to your local machine: `git clone https://github.com/mhmdomer/ecommerce-laravel.git && cd ecommerce-laravel` 24 | 1. copy `.example.env` to `.env` file: `cp .example.env .env` 25 | 1. create a new database and add the database credentials to your `.env` file 26 | 1. run `composer install` 27 | 1. run `npm install && npm run dev` 28 | 1. run `php artisan key:generate` 29 | 1. run `php artisan ecommerce:install` 30 | 1. run `php artisan serve` and then visit `http://127.0.0.1:8000/` 31 | 1. credentials to access admin panel (email: `admin@admin.com`, password: `password`) 32 | 1. after you login as admin, you can access the admin page from `http://127.0.0.1:8000/admin` 33 | - Home Page 34 | 35 | ![Screenshot (35)](https://user-images.githubusercontent.com/39973541/68545143-e8aeb280-03d2-11ea-8bb1-1c245150e432.png) 36 | 37 | - Shopping Page 38 | 39 | ![Screenshot (36)](https://user-images.githubusercontent.com/39973541/68545195-5bb82900-03d3-11ea-801f-40d1f8c3334a.png) 40 | 41 | - Cart Page 42 | 43 | ![Screenshot (37)](https://user-images.githubusercontent.com/39973541/68545206-82765f80-03d3-11ea-8c5d-95ce0fc68e83.png) 44 | 45 | - Checkout page 46 | 47 | ![Screenshot (38)](https://user-images.githubusercontent.com/39973541/68545217-9a4de380-03d3-11ea-8a97-18057d9ea3f2.png) 48 | 49 | - Admin Orders BREAD 50 | 51 | ![Screenshot (33)](https://user-images.githubusercontent.com/39973541/68546326-ab035700-03dd-11ea-860c-7912775e2359.png) 52 | 53 | - Admin Products BREAD 54 | 55 | ![Screenshot (34)](https://user-images.githubusercontent.com/39973541/68546338-d4bc7e00-03dd-11ea-9934-4c7329435f8a.png) 56 | -------------------------------------------------------------------------------- /app/Category.php: -------------------------------------------------------------------------------- 1 | hasMany('App\Product'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/Console/Commands/EcommerceInstall.php: -------------------------------------------------------------------------------- 1 | option('force')) { 42 | $this->proceed(); 43 | } else if($this->confirm('This will delete all your current data and database and install the default dummy data Are You Sure?')) { 44 | $this->proceed(); 45 | } 46 | } 47 | 48 | protected function proceed() { 49 | $linkFile = public_path('storage'); 50 | if(file_exists($linkFile)) { 51 | if(is_link($linkFile)){ 52 | unlink($linkFile); 53 | } 54 | } 55 | if(!file_exists(storage_path('app/public'))) { 56 | mkdir(storage_path('app/public/')); 57 | } 58 | $this->call('storage:link'); 59 | $copySuccess1 = File::copyDirectory(public_path('/images/products/dummy'), public_path('storage/products/dummy')); 60 | $copySuccess2 = File::copyDirectory(public_path('/images/users'), public_path('storage/users')); 61 | if($copySuccess1 && $copySuccess2) { 62 | $this->info('Images successfully moved to storage folder'); 63 | } 64 | $this->call('migrate:fresh', [ 65 | '--seed' => true 66 | ]); 67 | $this->info('cleared the database and seeded basic tables successfully'); 68 | $this->call('db:seed', [ 69 | '--class' => 'VoyagerDatabaseSeeder' 70 | ]); 71 | $this->call('db:seed', [ 72 | '--class' => 'VoyagerDummyDatabaseSeeder' 73 | ]); 74 | $this->call('db:seed', [ 75 | '--class' => 'VoyagerDatabaseSeederCustom' 76 | ]); 77 | $this->call('db:seed', [ 78 | '--class' => 'OrdersTableSeeder' 79 | ]); 80 | $this->call('db:seed', [ 81 | '--class' => 'OrderProductTableSeeder' 82 | ]); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/Console/Commands/HerokuSetup.php: -------------------------------------------------------------------------------- 1 | option('force')) { 42 | $this->proceed(); 43 | } else if($this->confirm('This will delete all your current data and database and install the default dummy data Are You Sure?')) { 44 | $this->proceed(); 45 | } 46 | } 47 | 48 | protected function proceed() { 49 | File::deleteDirectory(public_path('storage/products/dummy')); 50 | File::deleteDirectory(public_path('storage/users')); 51 | $this->info(file_exists(public_path('/images/products'))); 52 | $this->callSilent('storage:link'); 53 | $copySuccess1 = File::copyDirectory(public_path('/images/products'), public_path('storage/products/dummy')); 54 | $copySuccess2 = File::copyDirectory(public_path('/images/users'), public_path('storage/users')); 55 | if($copySuccess1 && $copySuccess2) { 56 | $this->info('Images successfully moved to storage folder'); 57 | } 58 | // $this->call('migrate:refresh', [ 59 | // '--seed' => true 60 | // ]); 61 | // $this->info('cleared the database and seeded basic tables successfully'); 62 | // $this->call('db:seed', [ 63 | // '--class' => 'VoyagerDatabaseSeeder' 64 | // ]); 65 | // $this->call('db:seed', [ 66 | // '--class' => 'VoyagerDummyDatabaseSeeder' 67 | // ]); 68 | // $this->call('db:seed', [ 69 | // '--class' => 'DataTypesTableSeederCustom' 70 | // ]); 71 | // $this->call('db:seed', [ 72 | // '--class' => 'DataRowsTableSeederCustom' 73 | // ]); 74 | // $this->call('db:seed', [ 75 | // '--class' => 'MenusTableSeederCustom' 76 | // ]); 77 | // $this->call('db:seed', [ 78 | // '--class' => 'MenuItemsTableSeederCustom' 79 | // ]); 80 | // $this->call('db:seed', [ 81 | // '--class' => 'PermissionsTableSeederCustom' 82 | // ]); 83 | // $this->call('db:seed', [ 84 | // '--class' => 'PermissionRoleTableSeederCustom' 85 | // ]); 86 | // $this->call('db:seed', [ 87 | // '--class' => 'SettingsTableSeederCustom' 88 | // ]); 89 | // $this->call('db:seed', [ 90 | // '--class' => 'OrdersTableSeeder' 91 | // ]); 92 | // $this->call('db:seed', [ 93 | // '--class' => 'OrderProductTableSeeder' 94 | // ]); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire') 28 | // ->hourly(); 29 | } 30 | 31 | /** 32 | * Register the commands for the application. 33 | * 34 | * @return void 35 | */ 36 | protected function commands() 37 | { 38 | $this->load(__DIR__.'/Commands'); 39 | 40 | require base_path('routes/console.php'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/CountryVisit.php: -------------------------------------------------------------------------------- 1 | increment('visits'); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Coupon.php: -------------------------------------------------------------------------------- 1 | first(); 12 | } 13 | 14 | public function discount($total) { 15 | if($this->type == 'fixed') { 16 | return $this->value; 17 | } else if($this->type == 'percent') { 18 | return ($this->percent_off / 100) * $total; 19 | } else { 20 | return 0; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Exceptions/Handler.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/ForgotPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('guest')->except('logout'); 40 | } 41 | 42 | /** 43 | * Redirect the user to the GitHub authentication page. 44 | * 45 | * @return \Illuminate\Http\Response 46 | */ 47 | public function redirectToProvider() 48 | { 49 | return Socialite::driver(request()->provider)->redirect(); 50 | } 51 | 52 | /** 53 | * Obtain the user information from GitHub. 54 | * 55 | * @return \Illuminate\Http\Response 56 | */ 57 | public function handleProviderCallback() 58 | { 59 | $provider = request()->provider; 60 | $providerUser = Socialite::driver($provider)->user(); 61 | if($providerUser->getEmail() == null) { 62 | $user = User::where($provider . '_id', $providerUser->getId())->first(); 63 | } else { 64 | $user = User::where('email', $providerUser->getEmail())->first(); 65 | } 66 | if($user && $user->$provider . '_id' == null) { 67 | $user->update([$provider . '_id' => $providerUser->getId()]); 68 | } 69 | if(!$user) { 70 | $user = User::create([ 71 | 'email' => $providerUser->getEmail(), 72 | 'name' => $providerUser->getName(), 73 | $provider . '_id' => $providerUser->getId(), 74 | ]); 75 | } 76 | 77 | auth()->login($user, true); 78 | 79 | return redirect($this->redirectTo); 80 | 81 | // $user->token; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/RegisterController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 41 | } 42 | 43 | /** 44 | * Get a validator for an incoming registration request. 45 | * 46 | * @param array $data 47 | * @return \Illuminate\Contracts\Validation\Validator 48 | */ 49 | protected function validator(array $data) 50 | { 51 | return Validator::make($data, [ 52 | 'name' => ['required', 'string', 'max:255'], 53 | 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 54 | 'password' => ['required', 'string', 'min:8', 'confirmed'], 55 | ]); 56 | } 57 | 58 | /** 59 | * Create a new user instance after a valid registration. 60 | * 61 | * @param array $data 62 | * @return \App\User 63 | */ 64 | protected function create(array $data) 65 | { 66 | return User::create([ 67 | 'name' => $data['name'], 68 | 'email' => $data['email'], 69 | 'password' => Hash::make($data['password']), 70 | ]); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/ResetPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 38 | $this->middleware('signed')->only('verify'); 39 | $this->middleware('throttle:6,1')->only('verify', 'resend'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Http/Controllers/CartController.php: -------------------------------------------------------------------------------- 1 | get(); 14 | return view('cart')->with('mightLike', $mightLike); 15 | } 16 | 17 | public function store() { 18 | session()->forget('coupon'); 19 | $duplicates = Cart::instance('default')->search(function($cartItem, $rowId) { 20 | return $cartItem->id == request()->id; 21 | }); 22 | $duplicatesLater = Cart::instance('saveForLater')->search(function($cartItem, $rowId) { 23 | return $cartItem->id == request()->id; 24 | }); 25 | if($duplicates->isNotEmpty()) { 26 | session()->flash('success', 'Item is already in your cart'); 27 | return redirect()->route('cart.index'); 28 | } else if($duplicatesLater->isNotEmpty()) { 29 | Cart::instance('saveForLater')->remove($duplicatesLater->first()->rowId); 30 | } 31 | Cart::instance('default')->add(request()->id, request()->name, 1, request()->price)->associate('App\Product'); 32 | session()->flash('success', 'product added to the cart'); 33 | return redirect()->route('cart.index'); 34 | } 35 | 36 | public function update($id) { 37 | session()->forget('coupon'); 38 | if(request()->productQuantity >= request()->quantity) { 39 | Cart::instance('default')->update($id, request()->quantity); 40 | session()->flash('success', 'quantity updated successfully!'); 41 | return response()->json(['success' => ''], 200); 42 | } 43 | session()->flash('error', 'not enough products'); 44 | return response()->json(['error' => ''], 405); 45 | } 46 | 47 | public function destroy($id, $cart) { 48 | if($cart == 'default') 49 | Cart::instance('default')->remove($id); 50 | else if($cart = 'saveForLater') 51 | Cart::instance('saveForLater')->remove($id); 52 | session()->flash('success', 'item has been removed'); 53 | return back(); 54 | } 55 | 56 | public function saveLater($id) { 57 | session()->forget('coupon'); 58 | $item = Cart::get($id); 59 | Cart::remove($id); 60 | $duplicates = Cart::instance('saveForLater')->search(function($cartItem, $rowId) use ($id) { 61 | return $rowId == $id; 62 | }); 63 | if($duplicates->isNotEmpty()) { 64 | session()->flash('success', 'Item is already saved for later'); 65 | return redirect()->route('cart.index'); 66 | } 67 | Cart::instance('saveForLater')->add($item->id, $item->name, 1, $item->price)->associate('App\Product'); 68 | session()->flash('success', 'Item has been saved for later'); 69 | return redirect()->route('cart.index'); 70 | } 71 | 72 | public function addToCart($id) { 73 | session()->forget('coupon'); 74 | $item = Cart::instance('saveForLater')->get($id); 75 | Cart::instance('saveForLater')->remove($id); 76 | $exist = Cart::instance('default')->search(function($cartItem, $rowId) use($item) { 77 | return $cartItem->id == $item->id; 78 | }); 79 | if($exist->isNotEmpty()) { 80 | session()->flash('success', 'Item is already in the cart'); 81 | return redirect()->route('cart.index'); 82 | } 83 | Cart::instance('default')->add($item->id, $item->name, 1, $item->price)->associate('App\Product'); 84 | session()->flash('success', 'item added to the cart'); 85 | return redirect()->route('cart.index'); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | validate($request, [ 14 | 'coupon_code' => 'required' 15 | ]); 16 | $coupon = Coupon::where('code', $request->coupon_code)->first(); 17 | if(!$coupon) return redirect()->route('checkout.index')->with('error', 'Invalid Coupon Code'); 18 | session()->put('coupon', [ 19 | 'code' => $coupon->code, 20 | 'discount' => $coupon->discount(Cart::instance('default')->subtotal()) 21 | ]); 22 | 23 | return redirect()->route('checkout.index')->withSuccess('Coupon applied successfully!'); 24 | } 25 | 26 | 27 | public function destroy() 28 | { 29 | session()->forget('coupon'); 30 | return redirect()->route('checkout.index')->with('success', 'Coupon has been removed'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Http/Controllers/HomeController.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 17 | } 18 | 19 | /** 20 | * Show the application dashboard. 21 | * 22 | * @return \Illuminate\Contracts\Support\Renderable 23 | */ 24 | public function index() 25 | { 26 | return view('home'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Controllers/ShopController.php: -------------------------------------------------------------------------------- 1 | category) { 17 | $category = Category::where('slug', request()->category)->get()->first(); 18 | $products = Product::where('category_id', $category->id); 19 | $categoryName = $category->name; 20 | } else if(request()->tag) { 21 | $tag = Tag::where('slug', request()->tag)->get()->first(); 22 | $products = $tag->products(); 23 | $tagName = $tag->name; 24 | } else { 25 | $products = Product::where('featured', true); 26 | $categoryName = 'Featured'; 27 | } 28 | if(request()->sort == 'low_high') { 29 | $products = $products->orderBy('price')->paginate($pagination); 30 | } else if(request()->sort == 'high_low') { 31 | $products = $products->orderBy('price', 'desc')->paginate($pagination); 32 | } else { 33 | $products = $products->inRandomOrder()->paginate($pagination); 34 | } 35 | $categories = Category::all(); 36 | $tags = Tag::all(); 37 | return view('shop')->with([ 38 | 'products' => $products, 39 | 'categories'=> $categories, 40 | 'tags'=> $tags, 41 | 'categoryName' => $categoryName ?? null, 42 | 'tagName' => $tagName ?? null 43 | ]); 44 | } 45 | 46 | public function show($slug) { 47 | $product = Product::where('slug', $slug)->firstOrFail(); 48 | $images = json_decode($product->images); 49 | $mightLike = Product::where('slug', '!=', $product->slug)->mightAlsoLike()->get(); 50 | $stockLevel = getStockLevel($product->quantity); 51 | return view('product')->with([ 52 | 'product' => $product, 53 | 'mightLike' => $mightLike, 54 | 'images' => $images, 55 | 'stockLevel' => $stockLevel 56 | ]); 57 | } 58 | 59 | public function search($query) { 60 | if(strlen($query) < 3) return back()->with('error', 'minimum query length is 3'); 61 | $products = Product::search($query)->paginate(10); 62 | return view('search')->with(['products' => $products, 'query' => $query]); 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /app/Http/Controllers/VisitsController.php: -------------------------------------------------------------------------------- 1 | limit(10) 13 | ->select('country', 'visits')->get(); 14 | 15 | $CountryVisit = CountryVisit::orderBy('visits', 'desc')->paginate(10); 16 | return view('admin.visits')->with([ 17 | 'CountryVisit' => $CountryVisit, 18 | 'topCountries' => $topCountries, 19 | ]); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Http/Controllers/Voyager/OrdersController.php: -------------------------------------------------------------------------------- 1 | getSlug($request); 35 | 36 | $dataType = Voyager::model('DataType')->where('slug', '=', $slug)->first(); 37 | 38 | $isSoftDeleted = false; 39 | 40 | if (strlen($dataType->model_name) != 0) { 41 | $model = app($dataType->model_name); 42 | 43 | // Use withTrashed() if model uses SoftDeletes and if toggle is selected 44 | if ($model && in_array(SoftDeletes::class, class_uses($model))) { 45 | $model = $model->withTrashed(); 46 | } 47 | if ($dataType->scope && $dataType->scope != '' && method_exists($model, 'scope'.ucfirst($dataType->scope))) { 48 | $model = $model->{$dataType->scope}(); 49 | } 50 | $dataTypeContent = call_user_func([$model, 'findOrFail'], $id); 51 | if ($dataTypeContent->deleted_at) { 52 | $isSoftDeleted = true; 53 | } 54 | } else { 55 | // If Model doest exist, get data from table name 56 | $dataTypeContent = DB::table($dataType->name)->where('id', $id)->first(); 57 | } 58 | 59 | // Replace relationships' keys for labels and create READ links if a slug is provided. 60 | $dataTypeContent = $this->resolveRelations($dataTypeContent, $dataType, true); 61 | 62 | // If a column has a relationship associated with it, we do not want to show that field 63 | $this->removeRelationshipField($dataType, 'read'); 64 | 65 | // Check permission 66 | $this->authorize('read', $dataTypeContent); 67 | 68 | // Check if BREAD is Translatable 69 | $isModelTranslatable = is_bread_translatable($dataTypeContent); 70 | 71 | $view = 'voyager::bread.read'; 72 | 73 | if (view()->exists("voyager::$slug.read")) { 74 | $view = "voyager::$slug.read"; 75 | } 76 | 77 | $products = Order::find($id)->products; 78 | 79 | return Voyager::view($view, compact('dataType', 'dataTypeContent', 'isModelTranslatable', 'isSoftDeleted', 'products')); 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /app/Http/Controllers/WelcomePageController.php: -------------------------------------------------------------------------------- 1 | take(6)->get(); 13 | $hotProducts = Product::inRandomOrder()->take(3)->get(); 14 | return view('welcome')->with([ 15 | 'products'=> $products, 16 | 'hotProducts' => $hotProducts 17 | ]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Http/Kernel.php: -------------------------------------------------------------------------------- 1 | [ 32 | \App\Http\Middleware\EncryptCookies::class, 33 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, 34 | \Illuminate\Session\Middleware\StartSession::class, 35 | // \Illuminate\Session\Middleware\AuthenticateSession::class, 36 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 37 | \App\Http\Middleware\VerifyCsrfToken::class, 38 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 39 | \App\Http\Middleware\VisitsMiddleware::class, 40 | ], 41 | 42 | 'api' => [ 43 | 'throttle:60,1', 44 | 'bindings', 45 | ], 46 | ]; 47 | 48 | /** 49 | * The application's route middleware. 50 | * 51 | * These middleware may be assigned to groups or used individually. 52 | * 53 | * @var array 54 | */ 55 | protected $routeMiddleware = [ 56 | 'auth' => \App\Http\Middleware\Authenticate::class, 57 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 58 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 59 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 60 | 'can' => \Illuminate\Auth\Middleware\Authorize::class, 61 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 62 | 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 63 | 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 64 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 65 | 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 66 | 'admin' => AdminMiddleware::class, 67 | ]; 68 | 69 | /** 70 | * The priority-sorted list of middleware. 71 | * 72 | * This forces non-global middleware to always be in the given order. 73 | * 74 | * @var array 75 | */ 76 | protected $middlewarePriority = [ 77 | \Illuminate\Session\Middleware\StartSession::class, 78 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 79 | \App\Http\Middleware\Authenticate::class, 80 | \Illuminate\Routing\Middleware\ThrottleRequests::class, 81 | \Illuminate\Session\Middleware\AuthenticateSession::class, 82 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 83 | \Illuminate\Auth\Middleware\Authorize::class, 84 | ]; 85 | } 86 | -------------------------------------------------------------------------------- /app/Http/Middleware/AdminMiddleware.php: -------------------------------------------------------------------------------- 1 | check() || !auth()->user()->role->name == 'admin') { 19 | abort(403, 'Sorry, You don\'t have permission to access this page'); 20 | } 21 | return $next($request); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | expectsJson()) { 18 | return route('login'); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Http/Middleware/CheckForMaintenanceMode.php: -------------------------------------------------------------------------------- 1 | check()) { 21 | return redirect('/'); 22 | } 23 | 24 | return $next($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | country; 28 | $visit = CountryVisit::firstOrCreate([ 29 | 'country' => $country 30 | ]); 31 | $visit->incrementVisits(); 32 | session(['visited' => 'visited']); 33 | Session::save(); 34 | } 35 | return $next($request); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/Http/Requests/CheckoutRequest.php: -------------------------------------------------------------------------------- 1 | user() ? 'required|email' : 'required|email|unique:users'; 27 | return [ 28 | 'email' => $emailValidation, 29 | 'name' => 'required|max:255|min:3', 30 | 'address' => 'required', 31 | 'city' => 'required', 32 | 'province' => 'required', 33 | 'postal_code' => 'required', 34 | 'phone' => 'required' 35 | ]; 36 | } 37 | 38 | public function messages() { 39 | return [ 40 | 'email.unique,users,email' => "You already have an account with this email address, Please Login" 41 | ]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/Mail/OrderPlaced.php: -------------------------------------------------------------------------------- 1 | order = $order; 24 | } 25 | 26 | /** 27 | * Build the message. 28 | * 29 | * @return $this 30 | */ 31 | public function build() 32 | { 33 | return $this->markdown('emails.orders.placed'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Order.php: -------------------------------------------------------------------------------- 1 | belongsTo('App\User'); 17 | } 18 | 19 | public function products() { 20 | // adding another field on the collection when accessing the order's products 21 | return $this->belongsToMany('App\Product')->withPivot('quantity'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/OrderProduct.php: -------------------------------------------------------------------------------- 1 | [ 16 | 'products.name' => 6, 17 | 'products.details' => 3, 18 | 'products.description' => 2, 19 | ], 20 | ]; 21 | 22 | protected $guarded = []; 23 | 24 | public function scopeMightAlsoLike($query) { 25 | return $query->inRandomOrder()->take(3); 26 | } 27 | 28 | public function category() { 29 | return $this->belongsTo('App\Category'); 30 | } 31 | 32 | public function tags() { 33 | return $this->belongsToMany('App\Tag'); 34 | } 35 | 36 | public function toSearchableArray() { 37 | $array = $this->toArray(); 38 | $extraFields = [ 39 | 'category' => $this->category->name 40 | ]; 41 | return array_merge($array, $extraFields); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/ProductTag.php: -------------------------------------------------------------------------------- 1 | 'App\Policies\ModelPolicy', 17 | ]; 18 | 19 | /** 20 | * Register any authentication / authorization services. 21 | * 22 | * @return void 23 | */ 24 | public function boot() 25 | { 26 | $this->registerPolicies(); 27 | 28 | // 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 19 | SendEmailVerificationNotification::class, 20 | ], 21 | ]; 22 | 23 | /** 24 | * Register any events for your application. 25 | * 26 | * @return void 27 | */ 28 | public function boot() 29 | { 30 | parent::boot(); 31 | 32 | // 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | mapApiRoutes(); 39 | 40 | $this->mapWebRoutes(); 41 | 42 | // 43 | } 44 | 45 | /** 46 | * Define the "web" routes for the application. 47 | * 48 | * These routes all receive session state, CSRF protection, etc. 49 | * 50 | * @return void 51 | */ 52 | protected function mapWebRoutes() 53 | { 54 | Route::middleware('web') 55 | ->namespace($this->namespace) 56 | ->group(base_path('routes/web.php')); 57 | } 58 | 59 | /** 60 | * Define the "api" routes for the application. 61 | * 62 | * These routes are typically stateless. 63 | * 64 | * @return void 65 | */ 66 | protected function mapApiRoutes() 67 | { 68 | Route::prefix('api') 69 | ->middleware('api') 70 | ->namespace($this->namespace) 71 | ->group(base_path('routes/api.php')); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/Tag.php: -------------------------------------------------------------------------------- 1 | belongsToMany('App\Product'); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/User.php: -------------------------------------------------------------------------------- 1 | 'datetime', 38 | ]; 39 | 40 | public function orders() { 41 | return $this->hasMany('App\Order'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/library/helper.php: -------------------------------------------------------------------------------- 1 | $limit ? substr($string, 0, $limit) . ' ...' : $string; 21 | } 22 | 23 | function getStockLevel($quantity) { 24 | if($quantity > setting('site.stock_threshold')) { 25 | return 'In Stock'; 26 | } else if($quantity <= setting('site.stock_threshold') && $quantity > 0) { 27 | return 'Low Stock'; 28 | } else { 29 | return 'Out Of Stock'; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 34 | 35 | $status = $kernel->handle( 36 | $input = new Symfony\Component\Console\Input\ArgvInput, 37 | new Symfony\Component\Console\Output\ConsoleOutput 38 | ); 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Shutdown The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once Artisan has finished running, we will fire off the shutdown events 46 | | so that any final work may be done by the application before we shut 47 | | down the process. This is the last thing to happen to the request. 48 | | 49 | */ 50 | 51 | $kernel->terminate($input, $status); 52 | 53 | exit($status); 54 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | singleton( 30 | Illuminate\Contracts\Http\Kernel::class, 31 | App\Http\Kernel::class 32 | ); 33 | 34 | $app->singleton( 35 | Illuminate\Contracts\Console\Kernel::class, 36 | App\Console\Kernel::class 37 | ); 38 | 39 | $app->singleton( 40 | Illuminate\Contracts\Debug\ExceptionHandler::class, 41 | App\Exceptions\Handler::class 42 | ); 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Return The Application 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This script returns the application instance. The instance is given to 50 | | the calling script so we can separate the building of the instances 51 | | from the actual running of the application and sending responses. 52 | | 53 | */ 54 | 55 | return $app; 56 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel/laravel", 3 | "type": "project", 4 | "description": "The Laravel Framework.", 5 | "keywords": [ 6 | "framework", 7 | "laravel" 8 | ], 9 | "license": "MIT", 10 | "require": { 11 | "php": "^8.0.2", 12 | "bumbummen99/shoppingcart": "^4.2", 13 | "cartalyst/stripe-laravel": "^14.0", 14 | "fideloper/proxy": "^4.0", 15 | "fzaninotto/faker": "^1.4", 16 | "laravel/framework": "^9.0", 17 | "laravel/socialite": "^5.0", 18 | "laravel/tinker": "^2.0", 19 | "laravel/ui": "^3.0", 20 | "mhmdomer/laravel-database-backup": "^1.1.0", 21 | "nicolaslopezj/searchable": "^1.12", 22 | "predis/predis": "^1.1", 23 | "rap2hpoutre/laravel-log-viewer": "^2.3", 24 | "tcg/voyager": "^1.3", 25 | "torann/geoip": "^3.0" 26 | }, 27 | "require-dev": { 28 | "barryvdh/laravel-debugbar": "^3.3", 29 | "spatie/laravel-ignition": "^1.0", 30 | "mockery/mockery": "^1.0", 31 | "nunomaduro/collision": "^6.1", 32 | "phpunit/phpunit": "^9.0" 33 | }, 34 | "config": { 35 | "optimize-autoloader": true, 36 | "preferred-install": "dist", 37 | "sort-packages": true 38 | }, 39 | "extra": { 40 | "laravel": { 41 | "dont-discover": [] 42 | } 43 | }, 44 | "autoload": { 45 | "files": [ 46 | "app/library/helper.php" 47 | ], 48 | "psr-4": { 49 | "App\\": "app/", 50 | "Database\\Factories\\": "database/factories/", 51 | "Database\\Seeders\\": "database/seeds/" 52 | }, 53 | "classmap": [ 54 | "database/seeds", 55 | "database/factories" 56 | ] 57 | }, 58 | "autoload-dev": { 59 | "psr-4": { 60 | "Tests\\": "tests/" 61 | } 62 | }, 63 | "minimum-stability": "dev", 64 | "prefer-stable": true, 65 | "scripts": { 66 | "post-autoload-dump": [ 67 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", 68 | "@php artisan package:discover --ansi" 69 | ], 70 | "post-root-package-install": [ 71 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" 72 | ], 73 | "post-create-project-cmd": [ 74 | "@php artisan key:generate --ansi" 75 | ] 76 | }, 77 | "repositories": { 78 | "hooks": { 79 | "type": "composer", 80 | "url": "https://larapack.io" 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => 'web', 18 | 'passwords' => 'users', 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | here which uses session storage and the Eloquent user provider. 29 | | 30 | | All authentication drivers have a user provider. This defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | mechanisms used by this application to persist your user's data. 33 | | 34 | | Supported: "session", "token" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | 44 | 'api' => [ 45 | 'driver' => 'token', 46 | 'provider' => 'users', 47 | 'hash' => false, 48 | ], 49 | ], 50 | 51 | /* 52 | |-------------------------------------------------------------------------- 53 | | User Providers 54 | |-------------------------------------------------------------------------- 55 | | 56 | | All authentication drivers have a user provider. This defines how the 57 | | users are actually retrieved out of your database or other storage 58 | | mechanisms used by this application to persist your user's data. 59 | | 60 | | If you have multiple user tables or models you may configure multiple 61 | | sources which represent each model / table. These sources may then 62 | | be assigned to any extra authentication guards you have defined. 63 | | 64 | | Supported: "database", "eloquent" 65 | | 66 | */ 67 | 68 | 'providers' => [ 69 | 'users' => [ 70 | 'driver' => 'eloquent', 71 | 'model' => App\User::class, 72 | ], 73 | 74 | // 'users' => [ 75 | // 'driver' => 'database', 76 | // 'table' => 'users', 77 | // ], 78 | ], 79 | 80 | /* 81 | |-------------------------------------------------------------------------- 82 | | Resetting Passwords 83 | |-------------------------------------------------------------------------- 84 | | 85 | | You may specify multiple password reset configurations if you have more 86 | | than one user table or model in the application and you want to have 87 | | separate password reset settings based on the specific user types. 88 | | 89 | | The expire time is the number of minutes that the reset token should be 90 | | considered valid. This security feature keeps tokens short-lived so 91 | | they have less time to be guessed. You may change this as needed. 92 | | 93 | */ 94 | 95 | 'passwords' => [ 96 | 'users' => [ 97 | 'provider' => 'users', 98 | 'table' => 'password_resets', 99 | 'expire' => 60, 100 | ], 101 | ], 102 | 103 | /* 104 | |-------------------------------------------------------------------------- 105 | | Password Confirmation Timeout 106 | |-------------------------------------------------------------------------- 107 | | 108 | | Here you may define the amount of seconds before a password confirmation 109 | | times out and the user is prompted to re-enter their password via the 110 | | confirmation screen. By default, the timeout lasts for three hours. 111 | | 112 | */ 113 | 114 | 'password_timeout' => 10800, 115 | 116 | ]; 117 | -------------------------------------------------------------------------------- /config/broadcasting.php: -------------------------------------------------------------------------------- 1 | env('BROADCAST_DRIVER', 'null'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Broadcast Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the broadcast connections that will be used 26 | | to broadcast events to other systems or over websockets. Samples of 27 | | each available type of connection are provided inside this array. 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'pusher' => [ 34 | 'driver' => 'pusher', 35 | 'key' => env('PUSHER_APP_KEY'), 36 | 'secret' => env('PUSHER_APP_SECRET'), 37 | 'app_id' => env('PUSHER_APP_ID'), 38 | 'options' => [ 39 | 'cluster' => env('PUSHER_APP_CLUSTER'), 40 | 'useTLS' => true, 41 | ], 42 | ], 43 | 44 | 'redis' => [ 45 | 'driver' => 'redis', 46 | 'connection' => 'default', 47 | ], 48 | 49 | 'log' => [ 50 | 'driver' => 'log', 51 | ], 52 | 53 | 'null' => [ 54 | 'driver' => 'null', 55 | ], 56 | 57 | ], 58 | 59 | ]; 60 | -------------------------------------------------------------------------------- /config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_DRIVER', 'file'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Cache Stores 26 | |-------------------------------------------------------------------------- 27 | | 28 | | Here you may define all of the cache "stores" for your application as 29 | | well as their drivers. You may even define multiple stores for the 30 | | same cache driver to group types of items stored in your caches. 31 | | 32 | */ 33 | 34 | 'stores' => [ 35 | 36 | 'apc' => [ 37 | 'driver' => 'apc', 38 | ], 39 | 40 | 'array' => [ 41 | 'driver' => 'array', 42 | ], 43 | 44 | 'database' => [ 45 | 'driver' => 'database', 46 | 'table' => 'cache', 47 | 'connection' => null, 48 | ], 49 | 50 | 'file' => [ 51 | 'driver' => 'file', 52 | 'path' => storage_path('framework/cache/data'), 53 | ], 54 | 55 | 'memcached' => [ 56 | 'driver' => 'memcached', 57 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), 58 | 'sasl' => [ 59 | env('MEMCACHED_USERNAME'), 60 | env('MEMCACHED_PASSWORD'), 61 | ], 62 | 'options' => [ 63 | // Memcached::OPT_CONNECT_TIMEOUT => 2000, 64 | ], 65 | 'servers' => [ 66 | [ 67 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'), 68 | 'port' => env('MEMCACHED_PORT', 11211), 69 | 'weight' => 100, 70 | ], 71 | ], 72 | ], 73 | 74 | 'redis' => [ 75 | 'driver' => 'redis', 76 | 'connection' => 'cache', 77 | ], 78 | 79 | 'dynamodb' => [ 80 | 'driver' => 'dynamodb', 81 | 'key' => env('AWS_ACCESS_KEY_ID'), 82 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 83 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 84 | 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), 85 | 'endpoint' => env('DYNAMODB_ENDPOINT'), 86 | ], 87 | 88 | ], 89 | 90 | /* 91 | |-------------------------------------------------------------------------- 92 | | Cache Key Prefix 93 | |-------------------------------------------------------------------------- 94 | | 95 | | When utilizing a RAM based store such as APC or Memcached, there might 96 | | be other applications utilizing the same cache. So, we'll specify a 97 | | value to get prefixed to all our keys so we can avoid collisions. 98 | | 99 | */ 100 | 101 | 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'), 102 | 103 | ]; 104 | -------------------------------------------------------------------------------- /config/cart.php: -------------------------------------------------------------------------------- 1 | 21, 16 | 17 | /* 18 | |-------------------------------------------------------------------------- 19 | | Shoppingcart database settings 20 | |-------------------------------------------------------------------------- 21 | | 22 | | Here you can set the connection that the shoppingcart should use when 23 | | storing and restoring a cart. 24 | | 25 | */ 26 | 27 | 'database' => [ 28 | 29 | 'connection' => null, 30 | 31 | 'table' => 'shoppingcart', 32 | 33 | ], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Destroy the cart on user logout 38 | |-------------------------------------------------------------------------- 39 | | 40 | | When this option is set to 'true' the cart will automatically 41 | | destroy all cart instances when the user logs out. 42 | | 43 | */ 44 | 45 | 'destroy_on_logout' => false, 46 | 47 | /* 48 | |-------------------------------------------------------------------------- 49 | | Default number format 50 | |-------------------------------------------------------------------------- 51 | | 52 | | This defaults will be used for the formatted numbers if you don't 53 | | set them in the method call. 54 | | 55 | */ 56 | 57 | 'format' => [ 58 | 59 | 'decimals' => 0, 60 | 61 | 'decimal_point' => '', 62 | 63 | 'thousand_separator' => '', 64 | 65 | ], 66 | 67 | ]; 68 | -------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DRIVER', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Default Cloud Filesystem Disk 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Many applications store files both locally and in the cloud. For this 24 | | reason, you may specify a default "cloud" driver here. This driver 25 | | will be bound as the Cloud disk implementation in the container. 26 | | 27 | */ 28 | 29 | 'cloud' => env('FILESYSTEM_CLOUD', 's3'), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Filesystem Disks 34 | |-------------------------------------------------------------------------- 35 | | 36 | | Here you may configure as many filesystem "disks" as you wish, and you 37 | | may even configure multiple disks of the same driver. Defaults have 38 | | been setup for each driver as an example of the required options. 39 | | 40 | | Supported Drivers: "local", "ftp", "sftp", "s3" 41 | | 42 | */ 43 | 44 | 'disks' => [ 45 | 46 | 'local' => [ 47 | 'driver' => 'local', 48 | 'root' => storage_path('app'), 49 | ], 50 | 51 | 'public' => [ 52 | 'driver' => 'local', 53 | 'root' => storage_path('app/public'), 54 | 'url' => env('APP_URL').'/storage', 55 | 'visibility' => 'public', 56 | ], 57 | 58 | 's3' => [ 59 | 'driver' => 's3', 60 | 'key' => env('AWS_ACCESS_KEY_ID'), 61 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 62 | 'region' => env('AWS_DEFAULT_REGION'), 63 | 'bucket' => env('AWS_BUCKET'), 64 | 'url' => env('AWS_URL'), 65 | ], 66 | 67 | ], 68 | 69 | ]; 70 | -------------------------------------------------------------------------------- /config/hashing.php: -------------------------------------------------------------------------------- 1 | 'bcrypt', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Bcrypt Options 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may specify the configuration options that should be used when 26 | | passwords are hashed using the Bcrypt algorithm. This will allow you 27 | | to control the amount of time it takes to hash the given password. 28 | | 29 | */ 30 | 31 | 'bcrypt' => [ 32 | 'rounds' => env('BCRYPT_ROUNDS', 10), 33 | ], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Argon Options 38 | |-------------------------------------------------------------------------- 39 | | 40 | | Here you may specify the configuration options that should be used when 41 | | passwords are hashed using the Argon algorithm. These will allow you 42 | | to control the amount of time it takes to hash the given password. 43 | | 44 | */ 45 | 46 | 'argon' => [ 47 | 'memory' => 1024, 48 | 'threads' => 2, 49 | 'time' => 2, 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /config/hooks.php: -------------------------------------------------------------------------------- 1 | env('HOOKS_ENABLED', true), 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /config/image.php: -------------------------------------------------------------------------------- 1 | 'gd' 19 | 20 | ]; 21 | -------------------------------------------------------------------------------- /config/logging.php: -------------------------------------------------------------------------------- 1 | env('LOG_CHANNEL', 'stack'), 21 | 22 | /* 23 | |-------------------------------------------------------------------------- 24 | | Log Channels 25 | |-------------------------------------------------------------------------- 26 | | 27 | | Here you may configure the log channels for your application. Out of 28 | | the box, Laravel uses the Monolog PHP logging library. This gives 29 | | you a variety of powerful log handlers / formatters to utilize. 30 | | 31 | | Available Drivers: "single", "daily", "slack", "syslog", 32 | | "errorlog", "monolog", 33 | | "custom", "stack" 34 | | 35 | */ 36 | 37 | 'channels' => [ 38 | 'stack' => [ 39 | 'driver' => 'stack', 40 | 'channels' => ['daily'], 41 | 'ignore_exceptions' => false, 42 | ], 43 | 44 | 'single' => [ 45 | 'driver' => 'single', 46 | 'path' => storage_path('logs/laravel.log'), 47 | 'level' => 'debug', 48 | ], 49 | 50 | 'daily' => [ 51 | 'driver' => 'daily', 52 | 'path' => storage_path('logs/laravel.log'), 53 | 'level' => 'debug', 54 | 'days' => 14, 55 | ], 56 | 57 | 'slack' => [ 58 | 'driver' => 'slack', 59 | 'url' => env('LOG_SLACK_WEBHOOK_URL'), 60 | 'username' => 'Laravel Log', 61 | 'emoji' => ':boom:', 62 | 'level' => 'critical', 63 | ], 64 | 65 | 'papertrail' => [ 66 | 'driver' => 'monolog', 67 | 'level' => 'debug', 68 | 'handler' => SyslogUdpHandler::class, 69 | 'handler_with' => [ 70 | 'host' => env('PAPERTRAIL_URL'), 71 | 'port' => env('PAPERTRAIL_PORT'), 72 | ], 73 | ], 74 | 75 | 'stderr' => [ 76 | 'driver' => 'monolog', 77 | 'handler' => StreamHandler::class, 78 | 'formatter' => env('LOG_STDERR_FORMATTER'), 79 | 'with' => [ 80 | 'stream' => 'php://stderr', 81 | ], 82 | ], 83 | 84 | 'syslog' => [ 85 | 'driver' => 'syslog', 86 | 'level' => 'debug', 87 | ], 88 | 89 | 'errorlog' => [ 90 | 'driver' => 'errorlog', 91 | 'level' => 'debug', 92 | ], 93 | 94 | 'null' => [ 95 | 'driver' => 'monolog', 96 | 'handler' => NullHandler::class, 97 | ], 98 | ], 99 | 100 | ]; 101 | -------------------------------------------------------------------------------- /config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_CONNECTION', 'sync'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Queue Connections 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure the connection information for each server that 24 | | is used by your application. A default configuration has been added 25 | | for each back-end shipped with Laravel. You are free to add more. 26 | | 27 | | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'sync' => [ 34 | 'driver' => 'sync', 35 | ], 36 | 37 | 'database' => [ 38 | 'driver' => 'database', 39 | 'table' => 'jobs', 40 | 'queue' => 'default', 41 | 'retry_after' => 90, 42 | ], 43 | 44 | 'beanstalkd' => [ 45 | 'driver' => 'beanstalkd', 46 | 'host' => 'localhost', 47 | 'queue' => 'default', 48 | 'retry_after' => 90, 49 | 'block_for' => 0, 50 | ], 51 | 52 | 'sqs' => [ 53 | 'driver' => 'sqs', 54 | 'key' => env('AWS_ACCESS_KEY_ID'), 55 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 56 | 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), 57 | 'queue' => env('SQS_QUEUE', 'your-queue-name'), 58 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 59 | ], 60 | 61 | 'redis' => [ 62 | 'driver' => 'redis', 63 | 'connection' => 'default', 64 | 'queue' => env('REDIS_QUEUE', 'default'), 65 | 'retry_after' => 90, 66 | 'block_for' => null, 67 | ], 68 | 69 | ], 70 | 71 | /* 72 | |-------------------------------------------------------------------------- 73 | | Failed Queue Jobs 74 | |-------------------------------------------------------------------------- 75 | | 76 | | These options configure the behavior of failed queue job logging so you 77 | | can control which database and table are used to store the jobs that 78 | | have failed. You may change them to any database / table you wish. 79 | | 80 | */ 81 | 82 | 'failed' => [ 83 | 'driver' => env('QUEUE_FAILED_DRIVER', 'database'), 84 | 'database' => env('DB_CONNECTION', 'mysql'), 85 | 'table' => 'failed_jobs', 86 | ], 87 | 88 | ]; 89 | -------------------------------------------------------------------------------- /config/scout.php: -------------------------------------------------------------------------------- 1 | env('SCOUT_DRIVER', 'algolia'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Index Prefix 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may specify a prefix that will be applied to all search index 26 | | names used by Scout. This prefix may be useful if you have multiple 27 | | "tenants" or applications sharing the same search infrastructure. 28 | | 29 | */ 30 | 31 | 'prefix' => env('SCOUT_PREFIX', ''), 32 | 33 | /* 34 | |-------------------------------------------------------------------------- 35 | | Queue Data Syncing 36 | |-------------------------------------------------------------------------- 37 | | 38 | | This option allows you to control if the operations that sync your data 39 | | with your search engines are queued. When this is set to "true" then 40 | | all automatic data syncing will get queued for better performance. 41 | | 42 | */ 43 | 44 | 'queue' => env('SCOUT_QUEUE', false), 45 | 46 | /* 47 | |-------------------------------------------------------------------------- 48 | | Chunk Sizes 49 | |-------------------------------------------------------------------------- 50 | | 51 | | These options allow you to control the maximum chunk size when you are 52 | | mass importing data into the search engine. This allows you to fine 53 | | tune each of these chunk sizes based on the power of the servers. 54 | | 55 | */ 56 | 57 | 'chunk' => [ 58 | 'searchable' => 500, 59 | 'unsearchable' => 500, 60 | ], 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Soft Deletes 65 | |-------------------------------------------------------------------------- 66 | | 67 | | This option allows to control whether to keep soft deleted records in 68 | | the search indexes. Maintaining soft deleted records can be useful 69 | | if your application still needs to search for the records later. 70 | | 71 | */ 72 | 73 | 'soft_delete' => false, 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | Algolia Configuration 78 | |-------------------------------------------------------------------------- 79 | | 80 | | Here you may configure your Algolia settings. Algolia is a cloud hosted 81 | | search engine which works great with Scout out of the box. Just plug 82 | | in your application ID and admin API key to get started searching. 83 | | 84 | */ 85 | 86 | 'algolia' => [ 87 | 'id' => env('ALGOLIA_APP_ID', ''), 88 | 'secret' => env('ALGOLIA_SECRET', ''), 89 | ], 90 | 91 | ]; 92 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 21 | ], 22 | 23 | 'postmark' => [ 24 | 'token' => env('POSTMARK_TOKEN'), 25 | ], 26 | 27 | 'ses' => [ 28 | 'key' => env('AWS_ACCESS_KEY_ID'), 29 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 30 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 31 | ], 32 | 33 | 'stripe' => [ 34 | 'model' => App\User::class, 35 | 'key' => env('STRIPE_KEY'), 36 | 'secret' => env('STRIPE_SECRET'), 37 | ], 38 | 39 | 'github' => [ 40 | 'client_id' => env('GITHUB_CLIENT_ID'), 41 | 'client_secret' => env('GITHUB_CLIENT_SECRET'), 42 | 'redirect' => env('GITHUB_CALLBACK'), 43 | ], 44 | 45 | 'facebook' => [ 46 | 'client_id' => env('FACEBOOK_CLIENT_ID'), 47 | 'client_secret' => env('FACEBOOK_CLIENT_SECRET'), 48 | 'redirect' => env('FACEBOOK_CALLBACK'), 49 | ], 50 | 51 | ]; 52 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | resource_path('views'), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => env( 32 | 'VIEW_COMPILED_PATH', 33 | realpath(storage_path('framework/views')) 34 | ), 35 | 36 | ]; 37 | -------------------------------------------------------------------------------- /config/voyager-hooks.php: -------------------------------------------------------------------------------- 1 | env('HOOKS_ENABLED', true), 6 | 7 | 'add-route' => true, 8 | 'add-hook-menu-item' => true, 9 | 'add-hook-permissions' => true, 10 | 'publish-vendor-files' => true, 11 | 12 | ]; 13 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | *.sqlite-journal 3 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | define(User::class, function (Faker $faker) { 20 | return [ 21 | 'name' => $faker->name, 22 | 'email' => $faker->unique()->safeEmail, 23 | 'email_verified_at' => now(), 24 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 25 | 'remember_token' => Str::random(10), 26 | ]; 27 | }); 28 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 16 | $table->string('name'); 17 | $table->string('email')->unique(); 18 | $table->timestamp('email_verified_at')->nullable(); 19 | $table->string('github_id')->nullable(); 20 | $table->string('facebook_id')->nullable(); 21 | $table->string('google_id')->nullable(); 22 | $table->string('password')->nullable(); 23 | $table->rememberToken(); 24 | $table->timestamps(); 25 | }); 26 | } 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('users'); 35 | } 36 | } -------------------------------------------------------------------------------- /database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 16 | $table->string('token'); 17 | $table->timestamp('created_at')->nullable(); 18 | }); 19 | } 20 | /** 21 | * Reverse the migrations. 22 | * 23 | * @return void 24 | */ 25 | public function down() 26 | { 27 | Schema::dropIfExists('password_resets'); 28 | } 29 | } -------------------------------------------------------------------------------- /database/migrations/2019_08_19_000000_create_failed_jobs_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 16 | $table->text('connection'); 17 | $table->text('queue'); 18 | $table->longText('payload'); 19 | $table->longText('exception'); 20 | $table->timestamp('failed_at')->useCurrent(); 21 | }); 22 | } 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('failed_jobs'); 31 | } 32 | } -------------------------------------------------------------------------------- /database/migrations/2019_10_16_185424_create_products_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('name')->unique(); 19 | $table->string('slug')->unique(); 20 | $table->string('details')->nullable(); 21 | $table->integer('price'); 22 | $table->text('description'); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('products'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2019_10_17_195112_create_categories_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('name')->unique(); 19 | $table->string('slug')->unique(); 20 | $table->timestamps(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('category'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /database/migrations/2019_10_17_195227_add_category_id_to_products_table.php: -------------------------------------------------------------------------------- 1 | string('image')->after('price'); 18 | $table->boolean('featured')->default(false)->after('image'); 19 | $table->unsignedBigInteger('category_id')->after('featured'); 20 | $table->foreign('category_id')->references('id')->on('category')->onDelete('cascade'); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::table('products', function (Blueprint $table) { 32 | $table->dropForeign('products_category_id_foreign'); 33 | $table->dropColumn('image'); 34 | $table->dropColumn('category_id'); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /database/migrations/2019_10_18_002421_create_coupons_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('code')->unique(); 19 | $table->string('type'); 20 | $table->integer('value')->nullable(); 21 | $table->integer('percent_off')->nullable(); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('coupons'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /database/migrations/2019_10_19_145706_add_images_column_to_products.php: -------------------------------------------------------------------------------- 1 | text('images')->nullable()->after('image'); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function down() 27 | { 28 | Schema::table('products', function (Blueprint $table) { 29 | $table->dropColumn('images'); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/migrations/2019_10_20_114921_create_tags_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('name')->unique(); 19 | $table->string('slug')->unique(); 20 | $table->timestamps(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('tags'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /database/migrations/2019_10_20_115306_create_products_tags_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->unsignedBigInteger('product_id'); 19 | $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade'); 20 | $table->unsignedBigInteger('tag_id'); 21 | $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade'); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('product_tag'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /database/migrations/2019_10_22_185425_create_orders_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->unsignedBigInteger('user_id')->nullable(); 19 | $table->foreign('user_id')->references('id')->on('users') 20 | ->onUpdate('cascade')->onDelete('set null'); 21 | $table->string('billing_email'); 22 | $table->string('billing_name'); 23 | $table->string('billing_address'); 24 | $table->string('billing_city'); 25 | $table->string('billing_province'); 26 | $table->string('billing_postalcode'); 27 | $table->string('billing_phone'); 28 | $table->string('billing_name_on_card'); 29 | $table->integer('billing_discount')->default(0); 30 | $table->string('billing_discount_code')->nullable(); 31 | $table->integer('billing_subtotal'); 32 | $table->integer('billing_tax'); 33 | $table->integer('billing_total'); 34 | $table->string('payment_gateway')->default('stripe'); 35 | $table->boolean('shipped')->default(false); 36 | $table->string('error')->nullable(); 37 | $table->timestamps(); 38 | }); 39 | } 40 | 41 | /** 42 | * Reverse the migrations. 43 | * 44 | * @return void 45 | */ 46 | public function down() 47 | { 48 | Schema::dropIfExists('orders'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /database/migrations/2019_10_22_190613_create_order_product_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->unsignedBigInteger('product_id')->nullable(); 19 | $table->foreign('product_id')->references('id')->on('products') 20 | ->onUpdate('cascade')->onDelete('set null'); 21 | $table->unsignedBigInteger('order_id')->nullable(); 22 | $table->foreign('order_id')->references('id')->on('orders') 23 | ->onUpdate('cascade')->onDelete('set null'); 24 | $table->unsignedInteger('quantity'); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('order_product'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/migrations/2019_11_09_002942_add_quantity_to_products_table.php: -------------------------------------------------------------------------------- 1 | unsignedInteger('quantity')->after('featured')->default(10); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function down() 27 | { 28 | Schema::table('products', function (Blueprint $table) { 29 | $table->dropColumn('quantity'); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/migrations/2020_06_27_012504_create_visits_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('country'); 19 | $table->unsignedBigInteger('visits')->default(0); 20 | $table->timestamps(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('visits'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /database/seeds/CategoryTableSeeder.php: -------------------------------------------------------------------------------- 1 | 'Laptops', 19 | 'slug' => 'laptops' 20 | ]); 21 | Category::create([ 22 | 'name' => 'Desktops', 23 | 'slug' => 'desktops' 24 | ]); 25 | Category::create([ 26 | 'name' => 'Phones', 27 | 'slug' => 'phones' 28 | ]); 29 | Category::create([ 30 | 'name' => 'Tablets', 31 | 'slug' => 'tablets' 32 | ]); 33 | Category::create([ 34 | 'name' => 'TVs', 35 | 'slug' => 'tvs' 36 | ]); 37 | Category::create([ 38 | 'name' => 'Cameras', 39 | 'slug' => 'cameras' 40 | ]); 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /database/seeds/CouponsTableSeeder.php: -------------------------------------------------------------------------------- 1 | 'ABC123', 19 | 'type' => 'fixed', 20 | 'value' => 20, 21 | ]); 22 | Coupon::create([ 23 | 'code' => 'DEF456', 24 | 'type' => 'percent', 25 | 'percent_off' => 40, 26 | ]); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /database/seeds/DataTypesTableSeeder.php: -------------------------------------------------------------------------------- 1 | dataType('slug', 'users'); 16 | if (!$dataType->exists) { 17 | $dataType->fill([ 18 | 'name' => 'users', 19 | 'display_name_singular' => __('voyager::seeders.data_types.user.singular'), 20 | 'display_name_plural' => __('voyager::seeders.data_types.user.plural'), 21 | 'icon' => 'voyager-person', 22 | 'model_name' => 'TCG\\Voyager\\Models\\User', 23 | 'policy_name' => 'TCG\\Voyager\\Policies\\UserPolicy', 24 | 'controller' => 'TCG\\Voyager\\Http\\Controllers\\VoyagerUserController', 25 | 'generate_permissions' => 1, 26 | 'description' => '', 27 | ])->save(); 28 | } 29 | 30 | $dataType = $this->dataType('slug', 'menus'); 31 | if (!$dataType->exists) { 32 | $dataType->fill([ 33 | 'name' => 'menus', 34 | 'display_name_singular' => __('voyager::seeders.data_types.menu.singular'), 35 | 'display_name_plural' => __('voyager::seeders.data_types.menu.plural'), 36 | 'icon' => 'voyager-list', 37 | 'model_name' => 'TCG\\Voyager\\Models\\Menu', 38 | 'controller' => '', 39 | 'generate_permissions' => 1, 40 | 'description' => '', 41 | ])->save(); 42 | } 43 | 44 | $dataType = $this->dataType('slug', 'roles'); 45 | if (!$dataType->exists) { 46 | $dataType->fill([ 47 | 'name' => 'roles', 48 | 'display_name_singular' => __('voyager::seeders.data_types.role.singular'), 49 | 'display_name_plural' => __('voyager::seeders.data_types.role.plural'), 50 | 'icon' => 'voyager-lock', 51 | 'model_name' => 'TCG\\Voyager\\Models\\Role', 52 | 'controller' => '', 53 | 'generate_permissions' => 1, 54 | 'description' => '', 55 | ])->save(); 56 | } 57 | } 58 | 59 | /** 60 | * [dataType description]. 61 | * 62 | * @param [type] $field [description] 63 | * @param [type] $for [description] 64 | * 65 | * @return [type] [description] 66 | */ 67 | protected function dataType($field, $for) 68 | { 69 | return DataType::firstOrNew([$field => $for]); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(CategoryTableSeeder::class); 17 | $this->call(TagsTableSeeder::class); 18 | $this->call(CouponsTableSeeder::class); 19 | $this->call(ProductsTableSeeder::class); 20 | $this->call(ProductTagSeeder::class); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /database/seeds/MenusTableSeeder.php: -------------------------------------------------------------------------------- 1 | 'admin', 19 | ]); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /database/seeds/MenusTableSeederCustom.php: -------------------------------------------------------------------------------- 1 | 'main', 19 | ]); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /database/seeds/OrderProductTableSeeder.php: -------------------------------------------------------------------------------- 1 | rand(1, 120), 21 | 'order_id' => Order::all()->random()->id, 22 | 'quantity' => rand(1,3), 23 | ]); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /database/seeds/OrdersTableSeeder.php: -------------------------------------------------------------------------------- 1 | rand(1, 2) == 1? 1 : null, 22 | 'billing_email' => $faker->email, 23 | 'billing_name' => $faker->userName, 24 | 'billing_address' => $faker->secondaryAddress, 25 | 'billing_city' => $faker->city, 26 | 'billing_province' => $faker->city, 27 | 'billing_postalcode' => $faker->postcode, 28 | 'billing_phone' => $faker->phoneNumber, 29 | 'billing_name_on_card' => $faker->userName, 30 | 'billing_discount' => 0, 31 | 'billing_discount_code' => null, 32 | 'billing_subtotal' => 1000, 33 | 'billing_tax' => 200, 34 | 'billing_total' => 1200, 35 | 'shipped' => rand(0,1), 36 | 'error' => $i%4 == 0 ? 'Error' : null, 37 | ]); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /database/seeds/PermissionRoleTableSeeder.php: -------------------------------------------------------------------------------- 1 | firstOrFail(); 19 | 20 | $permissions = Permission::all(); 21 | 22 | $role->permissions()->sync( 23 | $permissions->pluck('id')->all() 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /database/seeds/PermissionRoleTableSeederCustom.php: -------------------------------------------------------------------------------- 1 | firstOrFail(); 19 | 20 | $permissions = Permission::all(); 21 | 22 | $role->permissions()->sync( 23 | $permissions->pluck('id')->all() 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /database/seeds/PermissionsTableSeeder.php: -------------------------------------------------------------------------------- 1 | $key, 26 | 'table_name' => null, 27 | ]); 28 | } 29 | 30 | Permission::generateFor('menus'); 31 | 32 | Permission::generateFor('roles'); 33 | 34 | Permission::generateFor('users'); 35 | 36 | Permission::generateFor('settings'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/seeds/PermissionsTableSeederCustom.php: -------------------------------------------------------------------------------- 1 | $key, 26 | 'table_name' => null, 27 | ]); 28 | } 29 | 30 | Permission::generateFor('products'); 31 | 32 | Permission::generateFor('category'); 33 | 34 | Permission::generateFor('coupons'); 35 | 36 | Permission::generateFor('tags'); 37 | 38 | Permission::generateFor('product_tag'); 39 | 40 | Permission::generateFor('orders'); 41 | 42 | Permission::generateFor('country_visits'); 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /database/seeds/ProductTagSeeder.php: -------------------------------------------------------------------------------- 1 | rand(1, 120), 20 | 'tag_id' => rand(1, 4) 21 | ]); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /database/seeds/RolesTableSeeder.php: -------------------------------------------------------------------------------- 1 | 'admin']); 16 | if (!$role->exists) { 17 | $role->fill([ 18 | 'display_name' => __('voyager::seeders.roles.admin'), 19 | ])->save(); 20 | } 21 | 22 | $role = Role::firstOrNew(['name' => 'user']); 23 | if (!$role->exists) { 24 | $role->fill([ 25 | 'display_name' => __('voyager::seeders.roles.user'), 26 | ])->save(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /database/seeds/SettingsTableSeederCustom.php: -------------------------------------------------------------------------------- 1 | findSetting('site.stock_threshold'); 16 | if (!$setting->exists) { 17 | $setting->fill([ 18 | 'display_name' => 'Stock Threshold', 19 | 'value' => 5, 20 | 'details' => '', 21 | 'type' => 'number', 22 | 'order' => 6, 23 | 'group' => 'Site', 24 | ])->save(); 25 | } 26 | } 27 | 28 | /** 29 | * [setting description]. 30 | * 31 | * @param [type] $key [description] 32 | * 33 | * @return [type] [description] 34 | */ 35 | protected function findSetting($key) 36 | { 37 | return Setting::firstOrNew(['key' => $key]); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /database/seeds/TagsTableSeeder.php: -------------------------------------------------------------------------------- 1 | 'Tag ' . $i, 20 | 'slug' => 'tag-' . $i 21 | ]); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /database/seeds/UsersTableSeeder.php: -------------------------------------------------------------------------------- 1 | firstOrFail(); 21 | 22 | User::create([ 23 | 'name' => 'Admin', 24 | 'email' => 'admin@admin.com', 25 | 'password' => bcrypt(config('voyager.password')), 26 | 'remember_token' => Str::random(60), 27 | 'role_id' => $role->id, 28 | ]); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /database/seeds/VoyagerDatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(DataTypesTableSeeder::class); 22 | $this->call(DataRowsTableSeeder::class); 23 | $this->call(MenusTableSeeder::class); 24 | $this->call(MenuItemsTableSeeder::class); 25 | $this->call(RolesTableSeeder::class); 26 | $this->call(PermissionsTableSeeder::class); 27 | $this->call(PermissionRoleTableSeeder::class); 28 | $this->call(SettingsTableSeeder::class); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/seeds/VoyagerDatabaseSeederCustom.php: -------------------------------------------------------------------------------- 1 | call(DataTypesTableSeederCustom::class); 22 | $this->call(DataRowsTableSeederCustom::class); 23 | $this->call(MenusTableSeederCustom::class); 24 | $this->call(MenuItemsTableSeederCustom::class); 25 | $this->call(PermissionsTableSeederCustom::class); 26 | $this->call(PermissionRoleTableSeederCustom::class); 27 | $this->call(SettingsTableSeederCustom::class); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /database/seeds/VoyagerDummyDatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | seedersPath = database_path('seeds').'/'; 22 | $this->call(UsersTableSeeder::class); 23 | $this->call(PermissionRoleTableSeeder::class); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /hooks/hooks.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "mix", 6 | "watch": "mix watch", 7 | "watch-poll": "mix watch -- --watch-options-poll=1000", 8 | "hot": "mix watch --hot", 9 | "prod": "npm run production", 10 | "production": "mix --production" 11 | }, 12 | "devDependencies": { 13 | "axios": "^0.28.0", 14 | "bootstrap": "^4.5.0", 15 | "cross-env": "^5.1", 16 | "font-awesome": "^4.7.0", 17 | "jquery": "^3.5.1", 18 | "laravel-mix": "^6.0.49", 19 | "lodash": "^4.17.21", 20 | "popper.js": "^1.16.1", 21 | "resolve-url-loader": "^2.3.1", 22 | "sass": "^1.26.9", 23 | "sass-loader": "7.*", 24 | "vue": "^2.6.11", 25 | "vue-template-compiler": "^2.6.11" 26 | }, 27 | "dependencies": { 28 | "aos": "^3.0.0-beta.6", 29 | "chart.js": "^2.9.4", 30 | "font-awesome": "^4.7.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/Unit 14 | 15 | 16 | 17 | ./tests/Feature 18 | 19 | 20 | 21 | 22 | ./app 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Handle Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/favicon.ico -------------------------------------------------------------------------------- /public/fonts/vendor/font-awesome/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/fonts/vendor/font-awesome/fontawesome-webfont.eot -------------------------------------------------------------------------------- /public/fonts/vendor/font-awesome/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/fonts/vendor/font-awesome/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /public/fonts/vendor/font-awesome/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/fonts/vendor/font-awesome/fontawesome-webfont.woff -------------------------------------------------------------------------------- /public/fonts/vendor/font-awesome/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/fonts/vendor/font-awesome/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /public/images/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/images/cover.jpg -------------------------------------------------------------------------------- /public/images/not-found.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/images/not-found.jpg -------------------------------------------------------------------------------- /public/images/products/dummy/image0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/images/products/dummy/image0.jpg -------------------------------------------------------------------------------- /public/images/products/dummy/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/images/products/dummy/image1.jpg -------------------------------------------------------------------------------- /public/images/products/dummy/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/images/products/dummy/image2.jpg -------------------------------------------------------------------------------- /public/images/products/dummy/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/images/products/dummy/image3.jpg -------------------------------------------------------------------------------- /public/images/products/dummy/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/images/products/dummy/image4.jpg -------------------------------------------------------------------------------- /public/images/products/dummy/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/images/products/dummy/image5.jpg -------------------------------------------------------------------------------- /public/images/users/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/public/images/users/default.png -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | define('LARAVEL_START', microtime(true)); 11 | 12 | /* 13 | |-------------------------------------------------------------------------- 14 | | Register The Auto Loader 15 | |-------------------------------------------------------------------------- 16 | | 17 | | Composer provides a convenient, automatically generated class loader for 18 | | our application. We just need to utilize it! We'll simply require it 19 | | into the script here so that we don't have to worry about manual 20 | | loading any of our classes later on. It feels great to relax. 21 | | 22 | */ 23 | 24 | require __DIR__.'/../vendor/autoload.php'; 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | Turn On The Lights 29 | |-------------------------------------------------------------------------- 30 | | 31 | | We need to illuminate PHP development, so let us turn on the lights. 32 | | This bootstraps the framework and gets it ready for use, then it 33 | | will load up this application so that we can run it and send 34 | | the responses back to the browser and delight our users. 35 | | 36 | */ 37 | 38 | $app = require_once __DIR__.'/../bootstrap/app.php'; 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Run The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once we have the application, we can handle the incoming request 46 | | through the kernel, and send the associated response back to 47 | | the client's browser allowing them to enjoy the creative 48 | | and wonderful application we have prepared for them. 49 | | 50 | */ 51 | 52 | $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 53 | 54 | $response = $kernel->handle( 55 | $request = Illuminate\Http\Request::capture() 56 | ); 57 | 58 | $response->send(); 59 | 60 | $kernel->terminate($request, $response); 61 | -------------------------------------------------------------------------------- /public/mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/js/app.js": "/js/app.js", 3 | "/css/app.css": "/css/app.css" 4 | } 5 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /public/storage: -------------------------------------------------------------------------------- 1 | /home/mhmd/Personal/ecommerce-laravel/storage/app/public -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * First we will load all of this project's JavaScript dependencies which 3 | * includes Vue and other libraries. It is a great starting point when 4 | * building robust, powerful web applications using Vue and Laravel. 5 | */ 6 | 7 | require('./bootstrap'); 8 | require('./main'); 9 | 10 | window.Vue = require('vue'); 11 | 12 | /** 13 | * The following block of code may be used to automatically register your 14 | * Vue components. It will recursively scan this directory for the Vue 15 | * components and automatically register them with their "basename". 16 | * 17 | * Eg. ./components/ExampleComponent.vue -> 18 | */ 19 | 20 | // const files = require.context('./', true, /\.vue$/i) 21 | // files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default)) 22 | 23 | window.$ = require('jquery'); 24 | 25 | /** 26 | * Next, we will create a fresh Vue application instance and attach it to 27 | * the page. Then, you may begin adding components to this application 28 | * or customize the JavaScript scaffolding to fit your unique needs. 29 | */ 30 | 31 | -------------------------------------------------------------------------------- /resources/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | window._ = require('lodash'); 2 | 3 | try { 4 | window.Popper = require('popper.js').default; 5 | global.$ = global.jQuery = require('jquery'); 6 | console.log('k') 7 | 8 | require('bootstrap'); 9 | } catch (e) { 10 | console.log('an error accure') 11 | } 12 | 13 | window.AOS = require("aos"); 14 | 15 | window.Chart = require('chart.js'); 16 | 17 | window.axios = require('axios'); 18 | 19 | 20 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 21 | -------------------------------------------------------------------------------- /resources/js/main.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | $(".hero-text").animate({left: '0px', top: '30px'}, 1500); 3 | $('.heart').click(function (e) { 4 | e.preventDefault(); 5 | if($(this).find('i').attr('class') == 'fa fa-heart'){ 6 | $(this).find('i').attr('class' , 'fa fa-heart-o'); 7 | } else { 8 | $(this).find('i').attr('class' , 'fa fa-heart'); 9 | } 10 | }); 11 | $('.like').click(function (e) { 12 | e.preventDefault(); 13 | if($(this).find('i').attr('class') == 'fa fa-thumbs-up'){ 14 | $(this).find('i').attr('class' , 'fa fa-thumbs-o-up'); 15 | } else { 16 | $(this).find('i').attr('class' , 'fa fa-thumbs-up'); 17 | } 18 | }); 19 | $('.cart').click(function (e) { 20 | e.preventDefault(); 21 | if($(this).find('i').attr('class') == 'fa fa-shopping-cart'){ 22 | $(this).find('i').attr('class' , 'fal fa-shopping-cart'); 23 | } else { 24 | $(this).find('i').attr('class' , 'fa fa-shopping-cart'); 25 | } 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /resources/lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Your password has been reset!', 17 | 'sent' => 'We have e-mailed your password reset link!', 18 | 'token' => 'This password reset token is invalid.', 19 | 'user' => "We can't find a user with that e-mail address.", 20 | 21 | ]; 22 | -------------------------------------------------------------------------------- /resources/sass/_cart.scss: -------------------------------------------------------------------------------- 1 | .summary { 2 | padding: 1em; 3 | background-color: #ddd; 4 | } 5 | 6 | .inline-form-button { 7 | padding: 0; 8 | margin: 0; 9 | border: 0; 10 | background-color: #eee; 11 | font-size: 13px; 12 | color: #444; 13 | } 14 | 15 | .cart-option { 16 | margin: 0; 17 | } -------------------------------------------------------------------------------- /resources/sass/_checkout.scss: -------------------------------------------------------------------------------- 1 | .coupon { 2 | border: 1px solid #222; 3 | padding: 1em; 4 | } 5 | 6 | .quantity-square { 7 | border: 1px solid #222; 8 | padding: 0.5em; 9 | } -------------------------------------------------------------------------------- /resources/sass/_main.scss: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | font-family: 'Merienda One', cursive, sans-serif; 4 | background-color: #eee; 5 | } 6 | 7 | nav { 8 | opacity: 0.97; 9 | } 10 | 11 | .custom-border { 12 | border: 1px solid gainsboro; 13 | color: white; 14 | border-radius: 0; 15 | } 16 | 17 | .custom-border-n { 18 | border: 1px solid black; 19 | color: #222; 20 | border-radius: 0; 21 | margin-top:1em; 22 | } 23 | 24 | .custom-border-success { 25 | border-radius: 0; 26 | } 27 | 28 | .custom-border-n:hover { 29 | background-color: #222; 30 | color: white; 31 | } 32 | 33 | .product { 34 | margin-bottom: 1em; 35 | } 36 | 37 | button { 38 | margin-right: 1em; 39 | margin-top: 1em; 40 | margin-bottom: 1em; 41 | } 42 | 43 | .header { 44 | font-size: 1.7em; 45 | margin-bottom: 2em; 46 | } 47 | 48 | footer { 49 | color: white;; 50 | padding: 4em; 51 | } 52 | 53 | .footer { 54 | padding: 2em; 55 | } 56 | 57 | .card { 58 | padding: 0em; 59 | margin: 0em; 60 | } 61 | 62 | .footer-link { 63 | color: white; 64 | } 65 | 66 | .content-head { 67 | margin-bottom: 2em; 68 | } 69 | 70 | .card-body { 71 | align-content: center; 72 | justify-content: center; 73 | } 74 | 75 | a.custom-card, 76 | a.custom-card:hover { 77 | color: inherit; 78 | text-decoration: none; 79 | } 80 | 81 | .light-text { 82 | color: #444; 83 | } 84 | 85 | .suggestions { 86 | background-color: #ddd; 87 | } 88 | 89 | // from here 90 | 91 | .my-input { 92 | border-radius: 0; 93 | } 94 | 95 | .center { 96 | justify-content: center; 97 | align-content: center; 98 | } 99 | 100 | .cart-option { 101 | border: none; 102 | } 103 | 104 | .ais-SearchBox-submit, .ais-SearchBox-reset{ 105 | margin: 0; 106 | } 107 | 108 | .ais-Pagination { 109 | margin-top: 2em; 110 | margin-bottom: 2em; 111 | } 112 | 113 | .ais-Stats-text { 114 | margin-bottom: 1em; 115 | } 116 | 117 | .result-head { 118 | font-size: 0.9em; 119 | } 120 | 121 | .result-details { 122 | font-size: 0.6em; 123 | color: #444; 124 | } 125 | 126 | .result-price { 127 | font-size: 0.6em; 128 | color: #444; 129 | } 130 | 131 | .image-center { 132 | display: block; 133 | margin: 0 auto; 134 | } 135 | 136 | .ais-Hits-item { 137 | width: 100%; 138 | } -------------------------------------------------------------------------------- /resources/sass/_product.scss: -------------------------------------------------------------------------------- 1 | 2 | .product-image { 3 | padding: 0; 4 | } 5 | 6 | .image-thumbnails { 7 | display: grid; 8 | grid-template-columns: repeat(4, 1fr); 9 | grid-gap: 8px; 10 | margin-top: 13px; 11 | 12 | .active { 13 | border: 2px solid black; 14 | } 15 | } 16 | 17 | .image-thumbnail { 18 | width: 100%; 19 | height: 100%; 20 | overflow: hidden; 21 | border: 2px solid lightgray; 22 | 23 | &:hover { 24 | border: 2px solid #000; 25 | cursor: pointer; 26 | } 27 | } -------------------------------------------------------------------------------- /resources/sass/_shop.scss: -------------------------------------------------------------------------------- 1 | .filter-ul { 2 | padding: 0; 3 | background-color: #ddd; 4 | align-content: center; 5 | align-items: center; 6 | } 7 | 8 | .filter-ul li { 9 | border-bottom: 1px solid #bbb; 10 | color: #222; 11 | } 12 | .filter-ul li a{ 13 | padding: 0.8em; 14 | color: #222; 15 | text-decoration: none; 16 | display: block; 17 | } 18 | 19 | .filter-ul li:hover { 20 | background-color: #777; 21 | } 22 | 23 | .active-sort { 24 | background-color: green; 25 | color: white; 26 | border: 1px solid green; 27 | border-radius: 4px; 28 | padding: 0.3em; 29 | } 30 | 31 | .active-cat { 32 | background-color: #eee; 33 | color: #222; 34 | border-left: 1px solid #bbb; 35 | } 36 | 37 | li { 38 | list-style-type: none; 39 | } 40 | li a:hover { 41 | color: inherit; 42 | text-decoration: none; 43 | color: #222; 44 | } 45 | 46 | .filter-header { 47 | font-size: 1.2em; 48 | } -------------------------------------------------------------------------------- /resources/sass/_variables.scss: -------------------------------------------------------------------------------- 1 | // Body 2 | $body-bg: #f8fafc; 3 | 4 | // Typography 5 | $font-family-sans-serif: 'Nunito', sans-serif; 6 | $font-size-base: 0.9rem; 7 | $line-height-base: 1.6; 8 | 9 | // Colors 10 | $blue: #3490dc; 11 | $indigo: #6574cd; 12 | $purple: #9561e2; 13 | $pink: #f66d9b; 14 | $red: #e3342f; 15 | $orange: #f6993f; 16 | $yellow: #ffed4a; 17 | $green: #38c172; 18 | $teal: #4dc0b5; 19 | $cyan: #6cb2eb; 20 | -------------------------------------------------------------------------------- /resources/sass/_welcome.scss: -------------------------------------------------------------------------------- 1 | .hero-image { 2 | background-image: url("cover.jpg"); 3 | display: flex; 4 | flex-direction: column; 5 | min-height: 28em; 6 | height: 50%; 7 | align-self: center; 8 | background-repeat: no-repeat; 9 | background-size: cover; 10 | background-attachment: scroll; 11 | /* justify-content: center; */ 12 | margin-bottom: 2em; 13 | } 14 | 15 | .hero-content { 16 | overflow: visible; 17 | margin-left: 2em; 18 | margin-top:4em; 19 | color: white; 20 | } 21 | 22 | .show-more { 23 | display: flex; 24 | align-items: center; 25 | justify-content: center; 26 | } -------------------------------------------------------------------------------- /resources/sass/app.scss: -------------------------------------------------------------------------------- 1 | // Fonts 2 | @import url('https://fonts.googleapis.com/css?family=Nunito'); 3 | 4 | // Variables 5 | @import 'variables'; 6 | 7 | // Bootstrap 8 | @import '~bootstrap/scss/bootstrap'; 9 | 10 | @import "node_modules/font-awesome/scss/font-awesome.scss"; 11 | 12 | @import "main"; 13 | @import "cart"; 14 | @import "checkout"; 15 | @import "shop"; 16 | @import "welcome"; 17 | @import "product"; 18 | @import "~aos/dist/aos.css" -------------------------------------------------------------------------------- /resources/sass/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/resources/sass/cover.jpg -------------------------------------------------------------------------------- /resources/views/admin/visits.blade.php: -------------------------------------------------------------------------------- 1 | @extends('voyager::master') 2 | 3 | @section('head') 4 | 5 | @endsection 6 | @section('content') 7 | 8 |
9 |
10 |
11 | 12 |
13 |
14 | 15 |
16 |
17 |
18 | 19 |
20 |

21 | Country Visits: 22 |

23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | @foreach ($CountryVisit as $visit) 33 | 34 | 35 | 36 | 37 | @endforeach 38 | 39 |
CountryVisits
{{ $visit->country }}{{ $visit->visits }}
40 | {{ $CountryVisit->links() }} 41 |
42 |
43 | @endsection 44 | 45 | @section('javascript') 46 | 47 | 99 | 100 | 101 | @endsection 102 | -------------------------------------------------------------------------------- /resources/views/auth/login.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Login') }}
9 | 10 |
11 |
12 | @csrf 13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | @error('email') 21 | 22 | {{ $message }} 23 | 24 | @enderror 25 |
26 |
27 | 28 |
29 | 30 | 31 |
32 | 33 | 34 | @error('password') 35 | 36 | {{ $message }} 37 | 38 | @enderror 39 |
40 |
41 | 42 |
43 |
44 |
45 | 46 | 47 | 50 |
51 |
52 |
53 | 54 |
55 |
56 | 59 | {{-- 60 | Login with Github 61 | 62 | 63 | Login with Facebook 64 | --}} 65 | @if (str_replace(url('/'), '', url()->previous()) == '/cart') 66 | 67 | Guest checkout 68 | 69 | @endif 70 | 71 | @if (Route::has('password.request')) 72 | 73 | {{ __('Forgot Your Password?') }} 74 | 75 | @endif 76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | @endsection 85 | -------------------------------------------------------------------------------- /resources/views/auth/passwords/email.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Reset Password') }}
9 | 10 |
11 | @if (session('status')) 12 | 15 | @endif 16 | 17 |
18 | @csrf 19 | 20 |
21 | 22 | 23 |
24 | 25 | 26 | @error('email') 27 | 28 | {{ $message }} 29 | 30 | @enderror 31 |
32 |
33 | 34 |
35 |
36 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | @endsection 48 | -------------------------------------------------------------------------------- /resources/views/auth/passwords/reset.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Reset Password') }}
9 | 10 |
11 |
12 | @csrf 13 | 14 | 15 | 16 |
17 | 18 | 19 |
20 | 21 | 22 | @error('email') 23 | 24 | {{ $message }} 25 | 26 | @enderror 27 |
28 |
29 | 30 |
31 | 32 | 33 |
34 | 35 | 36 | @error('password') 37 | 38 | {{ $message }} 39 | 40 | @enderror 41 |
42 |
43 | 44 |
45 | 46 | 47 |
48 | 49 |
50 |
51 | 52 |
53 |
54 | 57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | @endsection 66 | -------------------------------------------------------------------------------- /resources/views/auth/register.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Register') }}
9 | 10 |
11 |
12 | @csrf 13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | @error('name') 21 | 22 | {{ $message }} 23 | 24 | @enderror 25 |
26 |
27 | 28 |
29 | 30 | 31 |
32 | 33 | 34 | @error('email') 35 | 36 | {{ $message }} 37 | 38 | @enderror 39 |
40 |
41 | 42 |
43 | 44 | 45 |
46 | 47 | 48 | @error('password') 49 | 50 | {{ $message }} 51 | 52 | @enderror 53 |
54 |
55 | 56 |
57 | 58 | 59 |
60 | 61 |
62 |
63 | 64 |
65 |
66 | 69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | @endsection 78 | -------------------------------------------------------------------------------- /resources/views/auth/verify.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Verify Your Email Address') }}
9 | 10 |
11 | @if (session('resent')) 12 | 15 | @endif 16 | 17 | {{ __('Before proceeding, please check your email for a verification link.') }} 18 | {{ __('If you did not receive the email') }}, 19 |
20 | @csrf 21 | . 22 |
23 |
24 |
25 |
26 |
27 |
28 | @endsection 29 | -------------------------------------------------------------------------------- /resources/views/emails/orders/placed.blade.php: -------------------------------------------------------------------------------- 1 | @component('mail::message') 2 | Your Order is sent successfully! 3 | 4 |

Order:

5 |
  • mail : {{ $order->billing_email }}
  • 6 |
  • Name : {{ $order->billing_name }}
  • 7 |
  • Total : {{ $order->billing_total }}
  • 8 |

    products:

    9 | @foreach ($order->products as $product) 10 | {{ $product->name }} : {{ $product->pivot->quantity }} 11 | @endforeach 12 | 13 | @component('mail::button', ['url' => config('app.url')]) 14 | Go To The Site 15 | @endcomponent 16 | 17 | Thanks,
    18 | {{ config('app.name') }} 19 | @endcomponent 20 | -------------------------------------------------------------------------------- /resources/views/errors/401.blade.php: -------------------------------------------------------------------------------- 1 | @extends('errors::minimal') 2 | 3 | @section('title', __('Unauthorized')) 4 | @section('code', '401') 5 | @section('message', __('Unauthorized')) 6 | -------------------------------------------------------------------------------- /resources/views/errors/403.blade.php: -------------------------------------------------------------------------------- 1 | @extends('errors::minimal') 2 | 3 | @section('title', __('Forbidden')) 4 | @section('code', '403') 5 | @section('message', __($exception->getMessage() ?: 'Forbidden')) 6 | -------------------------------------------------------------------------------- /resources/views/errors/404.blade.php: -------------------------------------------------------------------------------- 1 | @extends('errors::minimal') 2 | 3 | @section('title', __('Not Found')) 4 | @section('code', '404') 5 | @section('message', __('Not Found')) 6 | -------------------------------------------------------------------------------- /resources/views/errors/419.blade.php: -------------------------------------------------------------------------------- 1 | @extends('errors::minimal') 2 | 3 | @section('title', __('Page Expired')) 4 | @section('code', '419') 5 | @section('message', __('Page Expired')) 6 | -------------------------------------------------------------------------------- /resources/views/errors/429.blade.php: -------------------------------------------------------------------------------- 1 | @extends('errors::minimal') 2 | 3 | @section('title', __('Too Many Requests')) 4 | @section('code', '429') 5 | @section('message', __('Too Many Requests')) 6 | -------------------------------------------------------------------------------- /resources/views/errors/500.blade.php: -------------------------------------------------------------------------------- 1 | @extends('errors::minimal') 2 | 3 | @section('title', __('Service not available')) 4 | @section('message', __('Sorry, This demo site is unavailable right now.')) 5 | -------------------------------------------------------------------------------- /resources/views/errors/503.blade.php: -------------------------------------------------------------------------------- 1 | @extends('errors::minimal') 2 | 3 | @section('title', __('Service Unavailable')) 4 | @section('code', '503') 5 | @section('message', __($exception->getMessage() ?: 'Service Unavailable')) 6 | -------------------------------------------------------------------------------- /resources/views/errors/layout.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | @yield('title') 8 | 9 | 10 | 11 | 12 | 13 | 14 | 47 | 48 | 49 |
    50 |
    51 |
    52 | @yield('message') 53 |
    54 |
    55 |
    56 | 57 | 58 | -------------------------------------------------------------------------------- /resources/views/errors/minimal.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | @yield('title') 8 | 9 | 10 | 11 | 12 | 13 | 14 | 50 | 51 | 52 |
    53 |
    54 | @yield('code') 55 |
    56 | 57 |
    58 | @yield('message') 59 |
    60 |
    61 | 62 | 63 | -------------------------------------------------------------------------------- /resources/views/home.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @section('title', 'Home') 3 | @section('content') 4 |
    5 |
    6 |
    7 |
    8 |
    Dashboard
    9 | 10 |
    11 | @if (session('status')) 12 | 15 | @endif 16 | 17 | You are logged in! 18 |
    19 |
    20 |
    21 |
    22 |
    23 | @endsection 24 | -------------------------------------------------------------------------------- /resources/views/layouts/app.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | @include('partials.head') 4 | 9 | 10 |
    11 | @include('partials.nav') 12 |
    13 | @include('partials.session') 14 | @include('partials.errors') 15 | @yield('content') 16 |
    17 | @include('partials.footer') 18 |
    19 | 20 | @yield('scripts') 21 | 22 | -------------------------------------------------------------------------------- /resources/views/partials/errors.blade.php: -------------------------------------------------------------------------------- 1 | @if(count($errors) > 0) 2 | @foreach($errors->all() as $error) 3 |
    4 |
  • {!! $error !!}
  • 5 |
    6 | @endforeach 7 | @endif -------------------------------------------------------------------------------- /resources/views/partials/footer.blade.php: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /resources/views/partials/head.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {{ config('app.name', 'Laravel') }} | @yield('title') 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | @yield('stylesheet') 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /resources/views/partials/menu/main.blade.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/views/partials/might-like.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    You might also like

    4 | 5 |
    6 | @foreach ($mightLike as $product) 7 | 8 | 23 | 24 | @endforeach 25 |
    26 | 27 |
    28 |
    29 | -------------------------------------------------------------------------------- /resources/views/partials/nav.blade.php: -------------------------------------------------------------------------------- 1 | 55 |
    56 | 59 |
    60 | 73 | -------------------------------------------------------------------------------- /resources/views/partials/session.blade.php: -------------------------------------------------------------------------------- 1 | @if (session()->has('success')) 2 |
    3 |
  • {{ session()->get('success') }}
  • 4 |
    5 | @endif 6 | 7 | @if (session()->has('error')) 8 |
    9 |
  • {{ session()->get('error') }}
  • 10 |
    11 | @endif -------------------------------------------------------------------------------- /resources/views/product.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @section('title', $product->name) 3 | @section('content') 4 | 5 |
    6 | 7 |
    8 |
    9 |
    10 | 11 |
    12 |
    13 | @if ($images) 14 | 15 | @foreach ($images as $image) 16 |
    17 | 18 |
    19 | @endforeach 20 | @endif 21 |
    22 |
    23 |
    24 |

    {{ $product->name }}

    25 | {{ $stockLevel }} 26 |

    {{ $product->details }}

    27 |

    $ {{ format($product->price) }}

    28 |

    {!! $product->description !!}

    29 | @if ($product->quantity > 0) 30 |
    31 | @csrf() 32 | 33 | 34 | 35 | 36 |
    37 | @endif 38 |
    39 |
    40 | 41 |
    42 | @include('partials.might-like') 43 | 44 | 45 | @endsection 46 | 47 | @section('scripts') 48 | 49 | 69 | 70 | @endsection 71 | -------------------------------------------------------------------------------- /resources/views/search.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @section('title', 'Search') 3 | @section('content') 4 | 5 |
    6 |

    Showing {{ $products->count() }} results for {{ $query }} out of {{ $products->total() }}

    7 | @if ($products->total() == 0) 8 |
    9 | No products found for your search 10 |
    11 | @else 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | @foreach ($products as $product) 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | @endforeach 32 | 33 |
    NamePricedetailsDescriptionImage
    {{ $product->name }}${{ format($product->price) }}{{ $product->details }}{{ str_limit($product->description, 70) }}
    34 | @endif 35 | {{ $products->links() }} 36 |
    37 | 38 | @endsection -------------------------------------------------------------------------------- /resources/views/shop.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('title', 'Shop') 4 | @section('content') 5 | 6 | 7 |
    8 |
    9 | 10 |
    11 |

    12 | By Category 13 |

    14 | 19 |

    20 | By Tag 21 |

    22 | 27 |
    28 | 29 | 30 |
    31 |
    32 |
    33 |

    34 | {{ $categoryName }} 35 |

    36 |
    37 |
    38 | Price: 39 | Low to High 40 | High to Low 41 |
    42 |
    43 | 44 |
    45 | @foreach ($products as $product) 46 | 47 | 62 | 63 | @endforeach 64 |
    65 |
    66 | {{ $products->appends(request()->input())->links() }} 67 |
    68 | 69 |
    70 | 71 |
    72 |
    73 | 74 | 75 | @endsection 76 | -------------------------------------------------------------------------------- /resources/views/welcome.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @section('title', 'Welcome') 3 | @section('content') 4 | 5 | 6 |
    7 |
    8 |
    9 |

    10 | Welcome to the site Welcome to the site 11 |

    12 |

    Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquam, assumenda. Culpa, libero.

    13 | 14 | 15 |
    16 |
    17 |
    18 | 19 | 20 |
    21 |
    22 |

    Ecommerce

    23 |

    Lorem ipsum dolor sit amet consectetur adipisicing elit. Quam accusamus eos quibusdam, esse voluptates voluptatibus id corporis facere neque amet alias molestias itaque ex porro architecto blanditiis distinctio maxime laboriosam. 24 |

    25 |

    Featured Products

    26 | 27 |
    28 | @foreach ($products as $product) 29 | 30 | 45 | 46 | @endforeach 47 |
    48 | 49 |
    50 | 51 | 52 | 53 |
    54 |
    55 |

    Hot Sales

    56 | 57 |
    58 | @foreach ($hotProducts as $product) 59 | 60 | 75 | 76 | @endforeach 77 |
    78 | 79 |
    80 | 81 | 82 | @endsection 83 | -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | get('/user', function (Request $request) { 17 | return $request->user(); 18 | }); 19 | -------------------------------------------------------------------------------- /routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 16 | }); 17 | -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 18 | })->describe('Display an inspiring quote'); 19 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | middleware('admin'); 9 | 10 | // Shop and welcome 11 | Route::get('/', 'WelcomePageController@index')->name('welcome'); 12 | Route::get('/shop', 'ShopController@index')->name('shop.index'); 13 | Route::get('/shop/{product}', 'ShopController@show')->name('shop.show'); 14 | Route::get('/shop/search/{query}', 'ShopController@search')->name('shop.search'); 15 | 16 | 17 | // Cart 18 | Route::get('/cart', 'CartController@index')->name('cart.index'); 19 | Route::post('/cart', 'CartController@store')->name('cart.store'); 20 | Route::delete('/cart/{product}/{cart}', 'CartController@destroy')->name('cart.destroy'); 21 | Route::post('/cart/save-later/{product}', 'CartController@saveLater')->name('cart.save-later'); 22 | Route::post('/cart/add-to-cart/{product}', 'CartController@addToCart')->name('cart.add-to-cart'); 23 | Route::patch('/cart/{product}', 'CartController@update')->name('cart.update'); 24 | 25 | // checkout 26 | Route::get('/checkout', 'CheckoutController@index')->name('checkout.index'); 27 | Route::post('/checkout', 'CheckoutController@store')->name('checkout.store'); 28 | Route::get('/guest-checkout', 'CheckoutController@index')->name('checkout.guest'); 29 | 30 | // coupon 31 | Route::post('/coupon', 'CouponsController@store')->name('coupon.store'); 32 | Route::delete('/coupon/', 'CouponsController@destroy')->name('coupon.destroy'); 33 | 34 | // auth routes 35 | Auth::routes(); 36 | Route::get('/login/{provider}', 'Auth\LoginController@redirectToProvider'); 37 | Route::get('/login/{provider}/callback', 'Auth\LoginController@handleProviderCallback'); 38 | 39 | Route::get('/home', 'HomeController@index')->name('home'); 40 | 41 | Route::group(['prefix' => 'admin'], function () { 42 | Voyager::routes(); 43 | Route::get('/country_visits', 'VisitsController@index')->name('voyager.visits'); 44 | }); 45 | -------------------------------------------------------------------------------- /server.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | $uri = urldecode( 11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 12 | ); 13 | 14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the 15 | // built-in PHP web server. This provides a convenient way to test a Laravel 16 | // application without having installed a "real" web server software here. 17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { 18 | return false; 19 | } 20 | 21 | require_once __DIR__.'/public/index.php'; 22 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | public/products/September 2 | !.gitignore 3 | backup -------------------------------------------------------------------------------- /storage/app/public/products/September2020/7bmQiRD5DOS6QZTrprlb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/September2020/7bmQiRD5DOS6QZTrprlb.jpg -------------------------------------------------------------------------------- /storage/app/public/products/September2020/DKCbwzXCrbgRjlUJjlko.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/September2020/DKCbwzXCrbgRjlUJjlko.jpg -------------------------------------------------------------------------------- /storage/app/public/products/September2020/FHyZzRWZ0Ze0CAqiURkx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/September2020/FHyZzRWZ0Ze0CAqiURkx.jpg -------------------------------------------------------------------------------- /storage/app/public/products/September2020/gMuKbTUCz2AW9OS2Gqv1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/September2020/gMuKbTUCz2AW9OS2Gqv1.jpg -------------------------------------------------------------------------------- /storage/app/public/products/September2020/nx65t4W6tw17XFoPnfrb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/September2020/nx65t4W6tw17XFoPnfrb.jpg -------------------------------------------------------------------------------- /storage/app/public/products/September2020/xWLnSwcwkH4r7yhDn00F.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/September2020/xWLnSwcwkH4r7yhDn00F.jpg -------------------------------------------------------------------------------- /storage/app/public/products/dummy/image0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/dummy/image0.jpg -------------------------------------------------------------------------------- /storage/app/public/products/dummy/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/dummy/image1.jpg -------------------------------------------------------------------------------- /storage/app/public/products/dummy/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/dummy/image2.jpg -------------------------------------------------------------------------------- /storage/app/public/products/dummy/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/dummy/image3.jpg -------------------------------------------------------------------------------- /storage/app/public/products/dummy/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/dummy/image4.jpg -------------------------------------------------------------------------------- /storage/app/public/products/dummy/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/products/dummy/image5.jpg -------------------------------------------------------------------------------- /storage/app/public/users/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhmdomer/ecommerce-laravel/30f2f0bca61a1f51e31d3f01dbfe00305b3983af/storage/app/public/users/default.png -------------------------------------------------------------------------------- /storage/debugbar/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | config.php 2 | routes.php 3 | schedule-* 4 | compiled.php 5 | services.json 6 | events.scanned.php 7 | routes.scanned.php 8 | down 9 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 19 | 20 | return $app; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | get('/'); 18 | 19 | $response->assertStatus(200); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | const mix = require('laravel-mix'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Mix provides a clean, fluent API for defining some Webpack build steps 9 | | for your Laravel application. By default, we are compiling the Sass 10 | | file for the application as well as bundling up all the JS files. 11 | | 12 | */ 13 | 14 | mix.js('resources/js/app.js', 'public/js') 15 | .sass('resources/sass/app.scss', 'public/css'); 16 | --------------------------------------------------------------------------------