Explorar o código

Finish the coupon base.

Ferks-FK %!s(int64=2) %!d(string=hai) anos
pai
achega
640468acbe

+ 42 - 0
app/Console/Commands/DeleteExpiredCoupons.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Settings\CouponSettings;
+use App\Models\Coupon;
+use Carbon\Carbon;
+use Illuminate\Console\Command;
+
+
+class DeleteExpiredCoupons extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'coupons:delete';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Delete expired coupons from DB.';
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle(CouponSettings $couponSettings)
+    {
+        if ($couponSettings->delete_coupon_on_expires) {
+            $expired_coupons = Coupon::where('expires_at', '<=', Carbon::now(config('app.timezone')))->get();
+
+            foreach ($expired_coupons as $expired_coupon) {
+                $expired_coupon->delete();
+            }
+        }
+    }
+}

+ 2 - 0
app/Console/Kernel.php

@@ -16,6 +16,7 @@ class Kernel extends ConsoleKernel
     protected $commands = [
         Commands\ChargeCreditsCommand::class,
         Commands\ChargeServers::class,
+        Commands\DeleteExpiredCoupons::class,
     ];
 
     /**
@@ -29,6 +30,7 @@ class Kernel extends ConsoleKernel
         $schedule->command('servers:charge')->everyMinute();
         $schedule->command('cp:versioncheck:get')->daily();
         $schedule->command('payments:open:clear')->daily();
+        $schedule->command('coupons:delete')->daily();
 
         //log cronjob activity
         $schedule->call(function () {

+ 25 - 0
app/Events/CouponUsedEvent.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Events;
+
+use App\Models\Coupon;
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+
+class CouponUsedEvent
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    public Coupon $coupon;
+
+    /**
+     * Create a new event instance.
+     *
+     * @return void
+     */
+    public function __construct(Coupon $coupon)
+    {
+        $this->coupon = $coupon;
+    }
+}

+ 6 - 2
app/Extensions/PaymentGateways/PayPal/PayPalExtension.php

@@ -2,6 +2,7 @@
 
 namespace App\Extensions\PaymentGateways\PayPal;
 
+use App\Events\CouponUsedEvent;
 use App\Helpers\AbstractExtension;
 use App\Events\PaymentEvent;
 use App\Events\UserUpdateCreditsEvent;
@@ -56,6 +57,7 @@ class PayPalExtension extends AbstractExtension
 
         // Partner Discount.
         $price = $price - ($price * $discount / 100);
+        $price = number_format($price, 2);
 
         // create a new payment
         $payment = Payment::create([
@@ -82,12 +84,12 @@ class PayPalExtension extends AbstractExtension
                     "reference_id" => uniqid(),
                     "description" => $shopProduct->display . ($discount ? (" (" . __('Discount') . " " . $discount . '%)') : ""),
                     "amount" => [
-                        "value" => $shopProduct->getTotalPrice(),
+                        "value" => $price,
                         'currency_code' => strtoupper($shopProduct->currency_code),
                         'breakdown' => [
                             'item_total' => [
                                 'currency_code' => strtoupper($shopProduct->currency_code),
-                                'value' => number_format($price, 2),
+                                'value' => $price
                             ],
                             'tax_total' => [
                                 'currency_code' => strtoupper($shopProduct->currency_code),
@@ -158,6 +160,8 @@ class PayPalExtension extends AbstractExtension
                 if ($coupon_code) {
                     $coupon = new Coupon;
                     $coupon->incrementUses($coupon_code);
+
+                    event(new CouponUsedEvent($coupon));
                 }
 
                 event(new UserUpdateCreditsEvent($user));

+ 114 - 35
app/Http/Controllers/Admin/CouponController.php

@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Admin;
 
 use App\Http\Controllers\Controller;
 use App\Models\Coupon;
+use App\Settings\LocaleSettings;
 use App\Traits\Coupon as CouponTrait;
 use Illuminate\Http\Request;
 use Carbon\Carbon;
@@ -20,11 +21,13 @@ class CouponController extends Controller
      *
      * @return \Illuminate\Http\Response
      */
-    public function index()
+    public function index(LocaleSettings $localeSettings)
     {
         $this->checkPermission(self::READ_PERMISSION);
 
-        return view('admin.coupons.index');
+        return view('admin.coupons.index', [
+            'locale_datatables' => $localeSettings->datatables
+        ]);
     }
 
     /**
@@ -47,21 +50,12 @@ class CouponController extends Controller
      */
     public function store(Request $request)
     {
-        $coupon_code = $request->input('coupon_code');
-        $coupon_type = $request->input('coupon_type');
-        $coupon_value = $request->input('coupon_value');
-        $coupon_max_uses = $request->input('coupon_uses');
-        $coupon_datepicker = $request->input('datepicker');
+        $coupon_code = $request->input('code');
         $random_codes_amount = $request->input('range_codes');
-        $rules = [
-            "coupon_type" => "required|string|in:percentage,amount",
-            "coupon_uses" => "required|integer|digits_between:1,100",
-            "coupon_value" => "required|numeric|between:0,100",
-            "datepicker" => "required|date|after:" . Carbon::now()->format(Coupon::formatDate())
-        ];
+        $rules = $this->requestRules($request);
 
-        // If for some reason you pass both fields at once.
-        if ($coupon_code && $random_codes_amount) {
+         // If for some reason you pass both fields at once.
+         if ($coupon_code && $random_codes_amount) {
             return redirect()->back()->with('error', __('Only one of the two code inputs must be provided.'))->withInput($request->all());
         }
 
@@ -69,12 +63,6 @@ class CouponController extends Controller
             return redirect()->back()->with('error', __('At least one of the two code inputs must be provided.'))->withInput($request->all());
         }
 
-        if ($coupon_code) {
-            $rules['coupon_code'] = 'required|string|min:4';
-        } elseif ($random_codes_amount) {
-            $rules['range_codes'] = 'required|integer|digits_between:1,100';
-        }
-
         $request->validate($rules);
 
         if (array_key_exists('range_codes', $rules)) {
@@ -85,23 +73,17 @@ class CouponController extends Controller
             foreach ($coupons as $coupon) {
                 $data[] = [
                     'code' => $coupon,
-                    'type' => $coupon_type,
-                    'value' => $coupon_value,
-                    'max_uses' => $coupon_max_uses,
-                    'expires_at' => $coupon_datepicker,
+                    'type' => $request->input('type'),
+                    'value' => $request->input('value'),
+                    'max_uses' => $request->input('max_uses'),
+                    'expires_at' => $request->input('expires_at'),
                     'created_at' => Carbon::now(), // Does not fill in by itself when using the 'insert' method.
                     'updated_at' => Carbon::now()
                 ];
             }
             Coupon::insert($data);
         } else {
-            Coupon::create([
-                'code' => $coupon_code,
-                'type' => $coupon_type,
-                'value' => $coupon_value,
-                'max_uses' => $coupon_max_uses,
-                'expires_at' => $coupon_datepicker,
-            ]);
+            Coupon::create($request->except('_token'));
         }
 
         return redirect()->route('admin.coupons.index')->with('success', __("The coupon's was registered successfully."));
@@ -126,7 +108,12 @@ class CouponController extends Controller
      */
     public function edit(Coupon $coupon)
     {
-        //
+        $this->checkPermission(self::WRITE_PERMISSION);
+
+        return view('admin.coupons.edit', [
+            'coupon' => $coupon,
+            'expired_at' => $coupon->expires_at ? Carbon::createFromTimestamp($coupon->expires_at) : null
+        ]);
     }
 
     /**
@@ -138,7 +125,23 @@ class CouponController extends Controller
      */
     public function update(Request $request, Coupon $coupon)
     {
-        //
+        $coupon_code = $request->input('code');
+        $random_codes_amount = $request->input('range_codes');
+        $rules = $this->requestRules($request);
+
+        // If for some reason you pass both fields at once.
+        if ($coupon_code && $random_codes_amount) {
+            return redirect()->back()->with('error', __('Only one of the two code inputs must be provided.'))->withInput($request->all());
+        }
+
+        if (!$coupon_code && !$random_codes_amount) {
+            return redirect()->back()->with('error', __('At least one of the two code inputs must be provided.'))->withInput($request->all());
+        }
+
+        $request->validate($rules);
+        $coupon->update($request->except('_token'));
+
+        return redirect()->route('admin.coupons.index')->with('success', __('coupon has been updated!'));
     }
 
     /**
@@ -149,11 +152,87 @@ class CouponController extends Controller
      */
     public function destroy(Coupon $coupon)
     {
-        //
+        $this->checkPermission(self::WRITE_PERMISSION);
+        $coupon->delete();
+
+        return redirect()->back()->with('success', __('coupon has been removed!'));
+    }
+
+    private function requestRules(Request $request)
+    {
+        $coupon_code = $request->input('code');
+        $random_codes_amount = $request->input('range_codes');
+        $rules = [
+            "type" => "required|string|in:percentage,amount",
+            "max_uses" => "required|integer|digits_between:1,100",
+            "value" => "required|numeric|between:0,100",
+            "expires_at" => "nullable|date|after:" . Carbon::now()->format(Coupon::formatDate())
+        ];
+
+        if ($coupon_code) {
+            $rules['code'] = "required|string|min:4";
+        } elseif ($random_codes_amount) {
+            $rules['range_codes'] = 'required|integer|digits_between:1,100';
+        }
+
+        return $rules;
     }
 
     public function redeem(Request $request)
     {
         return $this->validateCoupon($request->user(), $request->input('couponCode'), $request->input('productId'));
     }
+
+    public function dataTable()
+    {
+        $query = Coupon::query();
+
+        return datatables($query)
+            ->addColumn('actions', function(Coupon $coupon) {
+                return '
+                    <a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.coupons.edit', $coupon->id).'" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
+
+                    <form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.coupons.destroy', $coupon->id).'">
+                        '.csrf_field().'
+                        '.method_field('DELETE').'
+                        <button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
+                    </form>
+                ';
+            })
+            ->addColumn('status', function(Coupon $coupon) {
+                $color = 'success';
+                $status = $coupon->getStatus();
+
+                if ($status != __('VALID')) {
+                    $color = 'danger';
+                }
+
+                return '<span class="badge badge-'.$color.'">'.str_replace('_', ' ', $status).'</span>';
+            })
+            ->editColumn('uses', function (Coupon $coupon) {
+                return "{$coupon->uses} / {$coupon->max_uses}";
+            })
+            ->editColumn('value', function (Coupon $coupon) {
+                if ($coupon->type === 'percentage') {
+                    return $coupon->value . "%";
+                }
+
+                return number_format($coupon->value, 2, '.', '');
+            })
+            ->editColumn('expires_at', function (Coupon $coupon) {
+                if (!$coupon->expires_at) {
+                    return __('Never');
+                }
+
+                return Carbon::createFromTimestamp($coupon->expires_at);
+            })
+            ->editColumn('created_at', function(Coupon $coupon) {
+                return Carbon::createFromTimeString($coupon->created_at);
+            })
+            ->editColumn('code', function (Coupon $coupon) {
+                return "<code>{$coupon->code}</code>";
+            })
+            ->rawColumns(['actions', 'code', 'status'])
+            ->make();
+    }
 }

+ 47 - 0
app/Listeners/CouponUsed.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Listeners;
+
+use App\Events\CouponUsedEvent;
+use App\Settings\CouponSettings;
+use Carbon\Carbon;
+
+class CouponUsed
+{
+    private $delete_coupon_on_expires;
+    private $delete_coupon_on_uses_reached;
+
+    /**
+     * Create the event listener.
+     *
+     * @return void
+     */
+    public function __construct(CouponSettings $couponSettings)
+    {
+        $this->delete_coupon_on_expires = $couponSettings->delete_coupon_on_expires;
+        $this->delete_coupon_on_uses_reached = $couponSettings->delete_coupon_on_uses_reached;
+    }
+
+    /**
+     * Handle the event.
+     *
+     * @param  \App\Events\CouponUsedEvent  $event
+     * @return void
+     */
+    public function handle(CouponUsedEvent $event)
+    {
+        if ($this->delete_coupon_on_expires) {
+            if (!is_null($event->coupon->expired_at)) {
+                if ($event->coupon->expires_at <= Carbon::now()->timestamp) {
+                    $event->coupon->delete();
+                }
+            }
+        }
+
+        if ($this->delete_coupon_on_uses_reached) {
+            if ($event->coupon->uses >= $event->coupon->max_uses) {
+                $event->coupon->delete();
+            }
+        }
+    }
+}

+ 5 - 0
app/Providers/EventServiceProvider.php

@@ -4,6 +4,8 @@ namespace App\Providers;
 
 use App\Events\PaymentEvent;
 use App\Events\UserUpdateCreditsEvent;
+use App\Events\CouponUsedEvent;
+use App\Listeners\CouponUsed;
 use App\Listeners\CreateInvoice;
 use App\Listeners\UnsuspendServers;
 use App\Listeners\UserPayment;
@@ -31,6 +33,9 @@ class EventServiceProvider extends ServiceProvider
             CreateInvoice::class,
             UserPayment::class,
         ],
+        CouponUsedEvent::class => [
+            CouponUsed::class
+        ],
         SocialiteWasCalled::class => [
             // ... other providers
             'SocialiteProviders\\Discord\\DiscordExtendSocialite@handle',

+ 16 - 2
app/Settings/CouponSettings.php

@@ -7,6 +7,8 @@ use Spatie\LaravelSettings\Settings;
 class CouponSettings extends Settings
 {
 	public ?int $max_uses_per_user;
+    public ?bool $delete_coupon_on_expires;
+    public ?bool $delete_coupon_on_uses_reached;
 
     public static function group(): string
     {
@@ -20,7 +22,9 @@ class CouponSettings extends Settings
     public static function getValidations()
     {
         return [
-            'max_uses_per_user' => 'required|integer'
+            'max_uses_per_user' => 'required|integer',
+            'delete_coupon_on_expires' => 'required|boolean',
+            'delete_coupon_on_uses_reached' => 'required|boolean',
         ];
     }
 
@@ -36,7 +40,17 @@ class CouponSettings extends Settings
             'max_uses_per_user' => [
                 'label' => 'Max Uses Per User',
                 'type' => 'number',
-                'description' => 'Maximum number of uses that a user can make of the same coupon.',
+                'description' => 'Maximum number of uses that a user can make of the same coupon.'
+            ],
+            'delete_coupon_on_expires' => [
+                'label' => 'Delete Coupon On Expires',
+                'type' => 'boolean',
+                'description' => 'Automatically deletes the coupon if it expires.'
+            ],
+            'delete_coupon_on_uses_reached' => [
+                'label' => 'Delete Coupon When Max Uses Reached',
+                'type' => 'boolean',
+                'description' => 'Delete a coupon as soon as its maximum usage is reached.'
             ]
         ];
     }

+ 4 - 0
database/settings/2023_05_12_170041_create_coupon_settings.php

@@ -7,10 +7,14 @@ return new class extends SettingsMigration
     public function up(): void
     {
         $this->migrator->add('coupon.max_uses_per_user', 1);
+        $this->migrator->add('coupon.delete_coupon_on_expires', false);
+        $this->migrator->add('coupon.delete_coupon_on_uses_reached', false);
     }
 
     public function down(): void
     {
         $this->migrator->delete('coupon.max_uses_per_user');
+        $this->migrator->delete('coupon.delete_coupon_on_expires');
+        $this->migrator->delete('coupon.delete_coupon_on_uses_reached');
     }
 };

+ 1 - 0
routes/web.php

@@ -201,6 +201,7 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
         Route::resource('partners', PartnerController::class);
 
         //coupons
+        Route::get('coupons/datatable', [CouponController::class, 'dataTable'])->name('coupons.datatable');
         Route::post('coupons/redeem', [CouponController::class, 'redeem'])->name('coupon.redeem');
         Route::resource('coupons', CouponController::class);
 

+ 38 - 38
themes/default/views/admin/coupons/create.blade.php

@@ -84,7 +84,7 @@
                   @enderror
                 </div>
                 <div id="coupon_code_element" class="form-group">
-                  <label for="coupon_code">
+                  <label for="code">
                     {{ __('Coupon Code') }}
                     <i
                       data-toggle="popover"
@@ -95,13 +95,13 @@
                   </label>
                   <input
                     type="text"
-                    id="coupon_code"
-                    name="coupon_code"
+                    id="code"
+                    name="code"
                     placeholder="SUMMER"
-                    class="form-control @error('coupon_code') is-invalid @enderror"
-                    value="{{ old('coupon_code') }}"
+                    class="form-control @error('code') is-invalid @enderror"
+                    value="{{ old('code') }}"
                   >
-                  @error('coupon_code')
+                  @error('code')
                     <div class="text-danger">
                       {{ $message }}
                     </div>
@@ -109,7 +109,7 @@
                 </div>
                 <div class="form-group">
                   <div class="custom-control mb-3 p-0">
-                    <label for="coupon_type">
+                    <label for="type">
                       {{ __('Coupon Type') }}
                       <i
                         data-toggle="popover"
@@ -119,17 +119,17 @@
                       </i>
                     </label>
                     <select
-                      name="coupon_type"
-                      id="coupon_type"
-                      class="custom-select @error('coupon_type') is_invalid @enderror"
+                      name="type"
+                      id="type"
+                      class="custom-select @error('type') is_invalid @enderror"
                       style="width: 100%; cursor: pointer;"
                       autocomplete="off"
                       required
                     >
-                      <option value="percentage" @if(old('coupon_type') == 'percentage') selected @endif>{{ __('Percentage') }}</option>
-                      <option value="amount" @if(old('coupon_type') == 'amount') selected @endif>{{ __('Amount') }}</option>
+                      <option value="percentage" @if(old('type') == 'percentage') selected @endif>{{ __('Percentage') }}</option>
+                      <option value="amount" @if(old('type') == 'amount') selected @endif>{{ __('Amount') }}</option>
                     </select>
-                    @error('coupon_type')
+                    @error('type')
                       <div class="text-danger">
                         {{ $message }}
                       </div>
@@ -138,7 +138,7 @@
                 </div>
                 <div class="form-group">
                   <div class="input-group d-flex flex-column">
-                    <label for="coupon_value">
+                    <label for="value">
                       {{ __('Coupon Value') }}
                       <i
                         data-toggle="popover"
@@ -149,18 +149,18 @@
                     </label>
                     <div class="d-flex">
                       <input
-                        name="coupon_value"
-                        id="coupon_value"
+                        name="value"
+                        id="value"
                         type="number"
                         step="any"
                         min="1"
                         max="100"
-                        class="form-control @error('coupon_value') is-invalid @enderror"
-                        value="{{ old('coupon_value') }}"
+                        class="form-control @error('value') is-invalid @enderror"
+                        value="{{ old('value') }}"
                       >
                       <span id="input_percentage" class="input-group-text">%</span>
                     </div>
-                    @error('coupon_value')
+                    @error('value')
                       <div class="text-danger">
                         {{ $message }}
                       </div>
@@ -168,7 +168,7 @@
                   </div>
                 </div>
                 <div class="form-group">
-                  <label for="coupon_uses">
+                  <label for="max_uses">
                     {{ __('Max uses') }}
                     <i
                       data-toggle="popover"
@@ -178,43 +178,43 @@
                     </i>
                   </label>
                   <input
-                    name="coupon_uses"
-                    id="coupon_uses"
+                    name="max_uses"
+                    id="max_uses"
                     type="number"
                     step="any"
                     min="1"
                     max="100"
-                    class="form-control @error('coupon_uses') is-invalid @enderror"
-                    value="{{ old('coupon_uses') }}"
+                    class="form-control @error('max_uses') is-invalid @enderror"
+                    value="{{ old('max_uses') }}"
                   >
-                  @error('coupon_uses')
+                  @error('max_uses')
                     <div class="text-danger">
                       {{ $message }}
                     </div>
                   @enderror
                 </div>
-                <div class="d-flex flex-column input-group form-group date" id="datepicker" data-target-input="nearest">
-                  <label for="datepicker">
+                <div class="d-flex flex-column input-group form-group date" id="expires_at" data-target-input="nearest">
+                  <label for="expires_at">
                     {{ __('Expires at') }}
                     <i
                       data-toggle="popover"
                       data-trigger="hover"
-                      data-content="{{__('The date when the coupon will expire.')}}"
+                      data-content="{{__('The date when the coupon will expire (If no date is provided, the coupon never expires).')}}"
                       class="fas fa-info-circle">
                     </i>
                   </label>
                   <div class="d-flex">
                     <input
-                      value="{{old('datepicker')}}"
-                      name="datepicker"
+                      value="{{ old('expires_at') }}"
+                      name="expires_at"
                       placeholder="yyyy-mm-dd hh:mm:ss"
                       type="text"
-                      class="form-control @error('datepicker') is-invalid @enderror datetimepicker-input"
-                      data-target="#datepicker"
+                      class="form-control @error('expires_at') is-invalid @enderror datetimepicker-input"
+                      data-target="#expires_at"
                     />
                     <div
                       class="input-group-append"
-                      data-target="#datepicker"
+                      data-target="#expires_at"
                       data-toggle="datetimepicker"
                     >
                       <div class="input-group-text">
@@ -222,7 +222,7 @@
                       </div>
                     </div>
                   </div>
-                  @error('datepicker')
+                  @error('expires_at')
                     <div class="text-danger">
                       {{ $message }}
                     </div>
@@ -244,7 +244,7 @@
 
   <script>
     $(document).ready(function() {
-      $('#datepicker').datetimepicker({
+      $('#expires_at').datetimepicker({
         format: 'Y-MM-DD HH:mm:ss',
         icons: {
           time: 'far fa-clock',
@@ -263,8 +263,8 @@
           $('#coupon_code_element').prop('disabled', true).hide()
           $('#range_codes_element').prop('disabled', false).show()
 
-          if ($('#coupon_code').val()) {
-            $('#coupon_code').prop('value', null)
+          if ($('#code').val()) {
+            $('#code').prop('value', null)
           }
 
         } else {
@@ -277,7 +277,7 @@
         }
       })
 
-      $('#coupon_type').change(function() {
+      $('#type').change(function() {
         if ($(this).val() == 'percentage') {
           $('#input_percentage').prop('disabled', false).show()
         } else {

+ 291 - 0
themes/default/views/admin/coupons/edit.blade.php

@@ -0,0 +1,291 @@
+@extends('layouts.main')
+
+@section('content')
+    <!-- CONTENT HEADER -->
+    <section class="content-header">
+        <div class="container-fluid">
+            <div class="row mb-2">
+                <div class="col-sm-6">
+                    <h1>{{__('Coupon')}}</h1>
+                </div>
+                <div class="col-sm-6">
+                    <ol class="breadcrumb float-sm-right">
+                        <li class="breadcrumb-item"><a href="{{route('home')}}">{{__('Dashboard')}}</a></li>
+                        <li class="breadcrumb-item"><a href="{{route('admin.coupons.index')}}">{{__('Coupon')}}</a>
+                        </li>
+                        <li class="breadcrumb-item"><a class="text-muted"
+                                                       href="{{route('admin.coupons.edit' , $coupon->id)}}">{{__('Edit')}}</a>
+                        </li>
+                    </ol>
+                </div>
+            </div>
+        </div>
+    </section>
+    <!-- END CONTENT HEADER -->
+
+    <!-- MAIN CONTENT -->
+    <section class="content">
+        <div class="container-fluid">
+
+            <div class="row">
+                <div class="col-lg-6">
+                    <div class="card">
+                        <div class="card-header">
+                            <h5 class="card-title">
+                                <i class="fas fa-money-check-alt mr-2"></i>{{__('Coupon details')}}
+                            </h5>
+                        </div>
+                        <div class="card-body">
+                          <form action="{{ route('admin.coupons.update', $coupon->id) }}" method="POST">
+                            @csrf
+                            @method('PATCH')
+
+                            <div class="d-flex flex-row-reverse">
+                              <div class="custom-control custom-switch">
+                                <input
+                                  type="checkbox"
+                                  id="random_codes"
+                                  name="random_codes"
+                                  class="custom-control-input"
+                                >
+                                <label for="random_codes" class="custom-control-label">
+                                  {{ __('Random Codes') }}
+                                  <i
+                                    data-toggle="popover"
+                                    data-trigger="hover"
+                                    data-content="{{__('Replace the creation of a single code with several at once with a custom field.')}}"
+                                    class="fas fa-info-circle">
+                                  </i>
+                                </label>
+                              </div>
+                            </div>
+                            <div id="range_codes_element" style="display: none;" class="form-group">
+                              <label for="range_codes">
+                                {{ __('Range Codes') }}
+                                <i
+                                  data-toggle="popover"
+                                  data-trigger="hover"
+                                  data-content="{{__('Generate a number of random codes.')}}"
+                                  class="fas fa-info-circle">
+                                </i>
+                              </label>
+                              <input
+                                type="number"
+                                id="range_codes"
+                                name="range_codes"
+                                step="any"
+                                min="1"
+                                max="100"
+                                class="form-control @error('range_codes') is-invalid @enderror"
+                              >
+                              @error('range_codes')
+                                <div class="text-danger">
+                                  {{ $message }}
+                                </div>
+                              @enderror
+                            </div>
+                            <div id="coupon_code_element" class="form-group">
+                              <label for="code">
+                                {{ __('Coupon Code') }}
+                                <i
+                                  data-toggle="popover"
+                                  data-trigger="hover"
+                                  data-content="{{__('The coupon code to be registered.')}}"
+                                  class="fas fa-info-circle">
+                                </i>
+                              </label>
+                              <input
+                                type="text"
+                                id="code"
+                                name="code"
+                                placeholder="SUMMER"
+                                class="form-control @error('code') is-invalid @enderror"
+                                value="{{ $coupon->code }}"
+                              >
+                              @error('code')
+                                <div class="text-danger">
+                                  {{ $message }}
+                                </div>
+                              @enderror
+                            </div>
+                            <div class="form-group">
+                              <div class="custom-control mb-3 p-0">
+                                <label for="type">
+                                  {{ __('Coupon Type') }}
+                                  <i
+                                    data-toggle="popover"
+                                    data-trigger="hover"
+                                    data-content="{{__('The way the coupon should discount.')}}"
+                                    class="fas fa-info-circle">
+                                  </i>
+                                </label>
+                                <select
+                                  name="type"
+                                  id="type"
+                                  class="custom-select @error('type') is_invalid @enderror"
+                                  style="width: 100%; cursor: pointer;"
+                                  autocomplete="off"
+                                  required
+                                >
+                                  <option value="percentage" @if($coupon->type == 'percentage') selected @endif>{{ __('Percentage') }}</option>
+                                  <option value="amount" @if($coupon->type == 'amount') selected @endif>{{ __('Amount') }}</option>
+                                </select>
+                                @error('type')
+                                  <div class="text-danger">
+                                    {{ $message }}
+                                  </div>
+                                @enderror
+                              </div>
+                            </div>
+                            <div class="form-group">
+                              <div class="input-group d-flex flex-column">
+                                <label for="value">
+                                  {{ __('Coupon Value') }}
+                                  <i
+                                    data-toggle="popover"
+                                    data-trigger="hover"
+                                    data-content="{{__('The value that the coupon will represent.')}}"
+                                    class="fas fa-info-circle">
+                                  </i>
+                                </label>
+                                <div class="d-flex">
+                                  <input
+                                    name="value"
+                                    id="value"
+                                    type="number"
+                                    step="any"
+                                    min="1"
+                                    max="100"
+                                    class="form-control @error('value') is-invalid @enderror"
+                                    value="{{ $coupon->value }}"
+                                  >
+                                  <span id="input_percentage" class="input-group-text">%</span>
+                                </div>
+                                @error('value')
+                                  <div class="text-danger">
+                                    {{ $message }}
+                                  </div>
+                                @enderror
+                              </div>
+                            </div>
+                            <div class="form-group">
+                              <label for="max_uses">
+                                {{ __('Max uses') }}
+                                <i
+                                  data-toggle="popover"
+                                  data-trigger="hover"
+                                  data-content="{{__('The maximum number of times the coupon can be used.')}}"
+                                  class="fas fa-info-circle">
+                                </i>
+                              </label>
+                              <input
+                                name="max_uses"
+                                id="max_uses"
+                                type="number"
+                                step="any"
+                                min="1"
+                                max="100"
+                                class="form-control @error('max_uses') is-invalid @enderror"
+                                value="{{ $coupon->max_uses }}"
+                              >
+                              @error('max_uses')
+                                <div class="text-danger">
+                                  {{ $message }}
+                                </div>
+                              @enderror
+                            </div>
+                            <div class="d-flex flex-column input-group form-group date" id="expires_at" data-target-input="nearest">
+                              <label for="expires_at">
+                                {{ __('Expires at') }}
+                                <i
+                                  data-toggle="popover"
+                                  data-trigger="hover"
+                                  data-content="{{__('The date when the coupon will expire (If no date is provided, the coupon never expires).')}}"
+                                  class="fas fa-info-circle">
+                                </i>
+                              </label>
+                              <div class="d-flex">
+                                <input
+                                  value="{{ $expired_at ?? '' }}"
+                                  name="expires_at"
+                                  placeholder="yyyy-mm-dd hh:mm:ss"
+                                  type="text"
+                                  class="form-control @error('expires_at') is-invalid @enderror datetimepicker-input"
+                                  data-target="#expires_at"
+                                />
+                                <div
+                                  class="input-group-append"
+                                  data-target="#expires_at"
+                                  data-toggle="datetimepicker"
+                                >
+                                  <div class="input-group-text">
+                                    <i class="fa fa-calendar"></i>
+                                  </div>
+                                </div>
+                              </div>
+                              @error('expires_at')
+                                <div class="text-danger">
+                                  {{ $message }}
+                                </div>
+                              @enderror
+                            </div>
+                            <div class="form-group text-right mb-0">
+                              <button type="submit" class="btn btn-primary">
+                                {{__('Submit')}}
+                              </button>
+                            </div>
+                          </form>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+        </div>
+    </section>
+    <!-- END CONTENT -->
+
+    <script>
+      $(document).ready(function() {
+        $('#expires_at').datetimepicker({
+          format: 'Y-MM-DD HH:mm:ss',
+          icons: {
+            time: 'far fa-clock',
+            date: 'far fa-calendar',
+            up: 'fas fa-arrow-up',
+            down: 'fas fa-arrow-down',
+            previous: 'fas fa-chevron-left',
+            next: 'fas fa-chevron-right',
+            today: 'fas fa-calendar-check',
+            clear: 'far fa-trash-alt',
+            close: 'far fa-times-circle'
+          }
+        });
+        $('#random_codes').change(function() {
+          if ($(this).is(':checked')) {
+            $('#coupon_code_element').prop('disabled', true).hide()
+            $('#range_codes_element').prop('disabled', false).show()
+
+            if ($('#code').val()) {
+              $('#code').prop('value', null)
+            }
+
+          } else {
+            $('#coupon_code_element').prop('disabled', false).show()
+            $('#range_codes_element').prop('disabled', true).hide()
+
+            if ($('#range_codes').val()) {
+              $('#range_codes').prop('value', null)
+            }
+          }
+        })
+
+        $('#type').change(function() {
+          if ($(this).val() == 'percentage') {
+            $('#input_percentage').prop('disabled', false).show()
+          } else {
+            $('#input_percentage').prop('disabled', true).hide()
+          }
+        })
+      })
+    </script>
+@endsection

+ 35 - 4
themes/default/views/admin/coupons/index.blade.php

@@ -42,10 +42,12 @@
                 <table id="datatable" class="table table-striped">
                     <thead>
                     <tr>
-                        <th>{{__('Partner discount')}}</th>
-                        <th>{{__('Registered user discount')}}</th>
-                        <th>{{__('Referral system commission')}}</th>
-                        <th>{{__('Created')}}</th>
+                        <th>{{__('Status')}}</th>
+                        <th>{{__('Code')}}</th>
+                        <th>{{__('Value')}}</th>
+                        <th>{{__('Used / Max Uses')}}</th>
+                        <th>{{__('Expires')}}</th>
+                        <th>{{__('Created At')}}</th>
                         <th>{{__('Actions')}}</th>
                     </tr>
                     </thead>
@@ -62,4 +64,33 @@
 
 </section>
 <!-- END CONTENT -->
+<script>
+  function submitResult() {
+    return confirm("{{__('Are you sure you wish to delete?')}}") !== false;
+  }
+
+  $(document).ready(function() {
+    $('#datatable').DataTable({
+      language: {
+        url: '//cdn.datatables.net/plug-ins/1.11.3/i18n/{{ $locale_datatables }}.json'
+      },
+      processing: true,
+      serverSide: true,
+      stateSave: true,
+      ajax: "{{route('admin.coupons.datatable')}}",
+      columns: [
+        {data: 'status'},
+        {data: 'code'},
+        {data: 'value'},
+        {data: 'uses'},
+        {data: 'expires_at'},
+        {data: 'created_at'},
+        {data: 'actions', sortable: false},
+      ],
+      fnDrawCallback: function( oSettings ) {
+        $('[data-toggle="popover"]').popover();
+      }
+    });
+  })
+</script>
 @endsection