Added voucher system
This commit is contained in:
parent
ed553674b2
commit
a7f8d71f92
142
app/Http/Controllers/Admin/VoucherController.php
Normal file
142
app/Http/Controllers/Admin/VoucherController.php
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Voucher;
|
||||||
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
|
use Illuminate\Contracts\View\Factory;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
|
class VoucherController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*
|
||||||
|
* @return Application|Factory|View
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('admin.vouchers.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @return Application|Factory|View
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
return view('admin.vouchers.create');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return RedirectResponse
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'memo' => 'sometimes|string|max:191',
|
||||||
|
'code' => 'required|string|alpha_dash|max:36',
|
||||||
|
'uses' => 'required|numeric|max:2147483647',
|
||||||
|
'credits' => 'required|numeric|between:0,99999999',
|
||||||
|
'expires_at' => 'required|date|after:today',
|
||||||
|
]);
|
||||||
|
|
||||||
|
Voucher::create($request->except('_token'));
|
||||||
|
|
||||||
|
return redirect()->route('admin.vouchers.index')->with('success', 'voucher has been created!');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*
|
||||||
|
* @param Voucher $voucher
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function show(Voucher $voucher)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*
|
||||||
|
* @param Voucher $voucher
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function edit(Voucher $voucher)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Voucher $voucher
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function update(Request $request, Voucher $voucher)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*
|
||||||
|
* @param Voucher $voucher
|
||||||
|
* @return RedirectResponse
|
||||||
|
*/
|
||||||
|
public function destroy(Voucher $voucher)
|
||||||
|
{
|
||||||
|
$voucher->delete();
|
||||||
|
return redirect()->back()->with('success', 'voucher has been removed!');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataTable()
|
||||||
|
{
|
||||||
|
$query = Voucher::with(['users']);
|
||||||
|
|
||||||
|
return datatables($query)
|
||||||
|
->addColumn('actions', function (Voucher $voucher) {
|
||||||
|
return '
|
||||||
|
<a data-content="Show" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.vouchers.show', $voucher->id) . '" class="btn btn-sm text-white btn-warning mr-1"><i class="fas fa-eye"></i></a>
|
||||||
|
<a data-content="Edit" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.vouchers.edit', $voucher->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.vouchers.destroy', $voucher->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 (Voucher $voucher) {
|
||||||
|
$color = 'success';
|
||||||
|
if ($voucher->getStatus() != 'VALID') $color = 'danger';
|
||||||
|
return '<span class="badge badge-'.$color.'">'. $voucher->getStatus() .'</span>';
|
||||||
|
})
|
||||||
|
->editColumn('uses', function (Voucher $voucher) {
|
||||||
|
$userCount = $voucher->users()->count();
|
||||||
|
return "{$userCount} / {$voucher->uses}";
|
||||||
|
})
|
||||||
|
->editColumn('credits', function (Voucher $voucher) {
|
||||||
|
return number_format($voucher->credits, 2, '.', '');
|
||||||
|
})
|
||||||
|
->editColumn('expires_at', function (Voucher $voucher) {
|
||||||
|
return $voucher->expires_at ? $voucher->expires_at->diffForHumans() : '';
|
||||||
|
})
|
||||||
|
->editColumn('code' , function (Voucher $voucher) {
|
||||||
|
return "<code>{$voucher->code}</code>";
|
||||||
|
})
|
||||||
|
->rawColumns(['actions' , 'code' , 'status'])
|
||||||
|
->make();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
57
app/Models/Voucher.php
Normal file
57
app/Models/Voucher.php
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Voucher
|
||||||
|
* @package App\Models
|
||||||
|
*/
|
||||||
|
class Voucher extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'memo',
|
||||||
|
'code',
|
||||||
|
'credits',
|
||||||
|
'uses',
|
||||||
|
'expires_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $dates = [
|
||||||
|
'expires_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static function boot()
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
static::deleting(function (Voucher $voucher) {
|
||||||
|
$voucher->users()->detach();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatus(){
|
||||||
|
if ($this->users()->count() >= $this->uses) return 'USES_LIMIT_REACHED';
|
||||||
|
if ($this->expires_at->isPast()) return 'EXPIRED';
|
||||||
|
return 'VALID';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return BelongsToMany
|
||||||
|
*/
|
||||||
|
public function users()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(User::class);
|
||||||
|
}
|
||||||
|
}
|
29
database/factories/VoucherFactory.php
Normal file
29
database/factories/VoucherFactory.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\voucher;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
class VoucherFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name of the factory's corresponding model.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $model = voucher::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function definition()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'credits' => $this->faker->numberBetween(100, 1000),
|
||||||
|
'expires_at' => $this->faker->dateTimeBetween(now(), '+30 days')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class CreateVouchersTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('vouchers', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('code', 36)->unique();
|
||||||
|
$table->string('memo')->nullable();
|
||||||
|
$table->unsignedFloat('credits', 10);
|
||||||
|
$table->unsignedInteger('uses')->default(1);
|
||||||
|
$table->timestamp('expires_at')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('vouchers');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class CreateUserVoucherTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('user_voucher', function (Blueprint $table) {
|
||||||
|
$table->foreignId('user_id')->constrained();
|
||||||
|
$table->foreignId('voucher_id')->constrained();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('user_voucher');
|
||||||
|
}
|
||||||
|
}
|
|
@ -72,7 +72,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="credits">Credits</label>
|
<label for="credits">Credits</label>
|
||||||
<input value="{{$user->credits}}" id="credits" name="credits" step="any" min="0"
|
<input value="{{$user->credits}}" id="credits" name="credits" step="any" min="0"
|
||||||
max="1000000"
|
max="999999"
|
||||||
type="number" class="form-control @error('credits') is-invalid @enderror"
|
type="number" class="form-control @error('credits') is-invalid @enderror"
|
||||||
required="required">
|
required="required">
|
||||||
@error('credits')
|
@error('credits')
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<h1>Products</h1>
|
<h1>Vouchers</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<ol class="breadcrumb float-sm-right">
|
<ol class="breadcrumb float-sm-right">
|
||||||
<li class="breadcrumb-item"><a href="{{route('home')}}">Dashboard</a></li>
|
<li class="breadcrumb-item"><a href="{{route('home')}}">Dashboard</a></li>
|
||||||
<li class="breadcrumb-item"><a href="{{route('admin.products.index')}}">Products</a></li>
|
<li class="breadcrumb-item"><a href="{{route('admin.products.index')}}">Vouchers</a></li>
|
||||||
<li class="breadcrumb-item"><a class="text-muted" href="{{route('admin.products.create')}}">Create</a>
|
<li class="breadcrumb-item"><a class="text-muted" href="{{route('admin.products.create')}}">Create</a>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
@ -28,162 +28,93 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5 class="card-title">
|
||||||
|
<i class="fas fa-money-check-alt mr-2"></i>Voucher details
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form action="{{route('admin.products.store')}}" method="POST">
|
<form action="{{route('admin.vouchers.store')}}" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
<div class="d-flex flex-row-reverse">
|
|
||||||
<div class="custom-control custom-switch">
|
|
||||||
<input type="checkbox" name="disabled" class="custom-control-input custom-control-input-danger" id="switch1">
|
|
||||||
<label class="custom-control-label" for="switch1">Disabled <i data-toggle="popover" data-trigger="hover" data-content="Will hide this option from being selected" class="fas fa-info-circle"></i></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">Name</label>
|
<label for="memo">Memo</label>
|
||||||
<input value="{{old('name')}}" id="name" name="name" type="text"
|
<input value="{{old('memo')}}" placeholder="Summer break voucher" id="memo"
|
||||||
class="form-control @error('name') is-invalid @enderror"
|
name="memo" type="text"
|
||||||
required="required">
|
class="form-control @error('memo') is-invalid @enderror">
|
||||||
@error('name')
|
@error('memo')
|
||||||
<div class="invalid-feedback">
|
<div class="text-danger">
|
||||||
{{$message}}
|
{{$message}}
|
||||||
</div>
|
</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="price">Price in credits</label>
|
<label for="credits">Credits *</label>
|
||||||
<input value="{{old('price')}}" id="price" name="price"
|
<input value="{{old('credits')}}" placeholder="500" id="credits"
|
||||||
type="number"
|
name="credits" type="number" step="any" min="0"
|
||||||
class="form-control @error('price') is-invalid @enderror"
|
max="999999"
|
||||||
required="required">
|
class="form-control @error('credits') is-invalid @enderror">
|
||||||
@error('price')
|
@error('credits')
|
||||||
<div class="invalid-feedback">
|
<div class="text-danger">
|
||||||
{{$message}}
|
{{$message}}
|
||||||
</div>
|
</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="memory">Memory</label>
|
|
||||||
<input value="{{old('memory')}}" id="memory" name="memory"
|
|
||||||
type="number"
|
|
||||||
class="form-control @error('memory') is-invalid @enderror"
|
|
||||||
required="required">
|
|
||||||
@error('memory')
|
|
||||||
<div class="invalid-feedback">
|
|
||||||
{{$message}}
|
|
||||||
</div>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="cpu">Cpu</label>
|
<label for="code">Code *</label>
|
||||||
<input value="{{old('cpu')}}" id="cpu" name="cpu"
|
<div class="input-group">
|
||||||
type="number"
|
<input value="{{old('code')}}" placeholder="SUMMER" id="code" name="code"
|
||||||
class="form-control @error('cpu') is-invalid @enderror"
|
|
||||||
required="required">
|
|
||||||
@error('cpu')
|
|
||||||
<div class="invalid-feedback">
|
|
||||||
{{$message}}
|
|
||||||
</div>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="swap">Swap</label>
|
|
||||||
<input value="{{old('swap')}}" id="swap" name="swap"
|
|
||||||
type="number"
|
|
||||||
class="form-control @error('swap') is-invalid @enderror"
|
|
||||||
required="required">
|
|
||||||
@error('swap')
|
|
||||||
<div class="invalid-feedback">
|
|
||||||
{{$message}}
|
|
||||||
</div>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="description">Description <i data-toggle="popover" data-trigger="hover" data-content="This is what the users sees" class="fas fa-info-circle"></i></label>
|
|
||||||
<textarea id="description" name="description"
|
|
||||||
type="text"
|
type="text"
|
||||||
class="form-control @error('description') is-invalid @enderror"
|
class="form-control @error('code') is-invalid @enderror"
|
||||||
required="required">{{old('description')}}</textarea>
|
required="required">
|
||||||
@error('description')
|
<div class="input-group-append">
|
||||||
<div class="invalid-feedback">
|
<button class="btn btn-info" onclick="setRandomCode()" type="button">
|
||||||
|
Random
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@error('code')
|
||||||
|
<div class="text-danger">
|
||||||
{{$message}}
|
{{$message}}
|
||||||
</div>
|
</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="disk">Disk</label>
|
<label for="uses">Uses *</label>
|
||||||
<input value="{{old('disk') ?? 1000}}" id="disk" name="disk"
|
<div class="input-group">
|
||||||
type="number"
|
<input value="{{old('uses') ?? 1}}" id="uses" min="1" max="2147483647"
|
||||||
class="form-control @error('disk') is-invalid @enderror"
|
name="uses" type="number"
|
||||||
|
class="form-control @error('uses') is-invalid @enderror"
|
||||||
required="required">
|
required="required">
|
||||||
@error('disk')
|
<div class="input-group-append">
|
||||||
<div class="invalid-feedback">
|
<button class="btn btn-info" onclick="setMaxUses()" type="button">Max
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@error('uses')
|
||||||
|
<div class="text-danger">
|
||||||
{{$message}}
|
{{$message}}
|
||||||
</div>
|
</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="io">IO</label>
|
<label for="expires_at">Expires at</label>
|
||||||
<input value="{{old('io') ?? 500}}" id="io" name="io"
|
<input value="{{old('expires_at')}}" id="expires_at" name="expires_at"
|
||||||
type="number"
|
type="datetime-local"
|
||||||
class="form-control @error('io') is-invalid @enderror"
|
class="form-control @error('expires_at') is-invalid @enderror">
|
||||||
required="required">
|
@error('expires_at')
|
||||||
@error('io')
|
<div class="text-danger">
|
||||||
<div class="invalid-feedback">
|
|
||||||
{{$message}}
|
{{$message}}
|
||||||
</div>
|
</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<label for="databases">Databases</label>
|
|
||||||
<input value="{{old('databases') ?? 1}}" id="databases"
|
|
||||||
name="databases"
|
|
||||||
type="number"
|
|
||||||
class="form-control @error('databases') is-invalid @enderror"
|
|
||||||
required="required">
|
|
||||||
@error('databases')
|
|
||||||
<div class="invalid-feedback">
|
|
||||||
{{$message}}
|
|
||||||
</div>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="backups">Backups</label>
|
|
||||||
<input value="{{old('backups') ?? 1}}" id="backups"
|
|
||||||
name="backups"
|
|
||||||
type="number"
|
|
||||||
class="form-control @error('backups') is-invalid @enderror"
|
|
||||||
required="required">
|
|
||||||
@error('backups')
|
|
||||||
<div class="invalid-feedback">
|
|
||||||
{{$message}}
|
|
||||||
</div>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="allocations">Allocations</label>
|
|
||||||
<input value="{{old('allocations') ?? 0}}"
|
|
||||||
id="allocations" name="allocations"
|
|
||||||
type="number"
|
|
||||||
class="form-control @error('allocations') is-invalid @enderror"
|
|
||||||
required="required">
|
|
||||||
@error('allocations')
|
|
||||||
<div class="invalid-feedback">
|
|
||||||
{{$message}}
|
|
||||||
</div>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group text-right">
|
<div class="form-group text-right">
|
||||||
<button type="submit" class="btn btn-primary">
|
<button type="submit" class="btn btn-primary">
|
||||||
|
@ -201,5 +132,30 @@
|
||||||
<!-- END CONTENT -->
|
<!-- END CONTENT -->
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function setMaxUses() {
|
||||||
|
let element = document.getElementById('uses')
|
||||||
|
element.value = element.max;
|
||||||
|
console.log(element.max)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function setRandomCode() {
|
||||||
|
let element = document.getElementById('code')
|
||||||
|
element.value = getRandomCode(36)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandomCode(length) {
|
||||||
|
let result = '';
|
||||||
|
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-';
|
||||||
|
let charactersLength = characters.length;
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() *
|
||||||
|
charactersLength));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<ol class="breadcrumb float-sm-right">
|
<ol class="breadcrumb float-sm-right">
|
||||||
<li class="breadcrumb-item"><a href="{{route('home')}}">Dashboard</a></li>
|
<li class="breadcrumb-item"><a href="{{route('home')}}">Dashboard</a></li>
|
||||||
<li class="breadcrumb-item"><a href="{{route('admin.products.index')}}">Vouchers</a></li>
|
<li class="breadcrumb-item"><a href="{{route('admin.products.index')}}">Vouchers</a></li>
|
||||||
<li class="breadcrumb-item"><a class="text-muted" href="{{route('admin.products.create')}}">Create</a>
|
<li class="breadcrumb-item"><a class="text-muted" href="{{route('admin.products.edit' , $voucher->id)}}">Edit</a>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,12 +34,13 @@
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form action="{{route('admin.vouchers.store')}}" method="POST">
|
<form action="{{route('admin.vouchers.update' , $voucher->id)}}" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
|
@method('PATCH')
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="memo">Memo</label>
|
<label for="memo">Memo</label>
|
||||||
<input value="{{old('memo')}}" placeholder="Summer break voucher" id="memo"
|
<input value="{{ $voucher->memo }}" placeholder="Summer break voucher" id="memo"
|
||||||
name="memo" type="text"
|
name="memo" type="text"
|
||||||
class="form-control @error('memo') is-invalid @enderror">
|
class="form-control @error('memo') is-invalid @enderror">
|
||||||
@error('memo')
|
@error('memo')
|
||||||
|
@ -51,7 +52,7 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="credits">Credits *</label>
|
<label for="credits">Credits *</label>
|
||||||
<input value="{{old('credits')}}" placeholder="500" id="credits"
|
<input value="{{ $voucher->credits }}" placeholder="500" id="credits"
|
||||||
name="credits" type="number" step="any" min="0"
|
name="credits" type="number" step="any" min="0"
|
||||||
max="999999"
|
max="999999"
|
||||||
class="form-control @error('credits') is-invalid @enderror">
|
class="form-control @error('credits') is-invalid @enderror">
|
||||||
|
@ -66,7 +67,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="code">Code *</label>
|
<label for="code">Code *</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input value="{{old('code')}}" placeholder="SUMMER" id="code" name="code"
|
<input value="{{ $voucher->code }}" placeholder="SUMMER" id="code" name="code"
|
||||||
type="text"
|
type="text"
|
||||||
class="form-control @error('code') is-invalid @enderror"
|
class="form-control @error('code') is-invalid @enderror"
|
||||||
required="required">
|
required="required">
|
||||||
|
@ -86,7 +87,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="uses">Uses *</label>
|
<label for="uses">Uses *</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input value="{{old('uses') ?? 1}}" id="uses" min="1" max="2147483647"
|
<input value="{{ $voucher->uses }}" id="uses" min="1" max="2147483647"
|
||||||
name="uses" type="number"
|
name="uses" type="number"
|
||||||
class="form-control @error('uses') is-invalid @enderror"
|
class="form-control @error('uses') is-invalid @enderror"
|
||||||
required="required">
|
required="required">
|
||||||
|
@ -105,7 +106,7 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="expires_at">Expires at</label>
|
<label for="expires_at">Expires at</label>
|
||||||
<input value="{{old('expires_at')}}" id="expires_at" name="expires_at"
|
<input value="{{ $voucher->expires_at }}" id="expires_at" name="expires_at"
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
class="form-control @error('expires_at') is-invalid @enderror">
|
class="form-control @error('expires_at') is-invalid @enderror">
|
||||||
@error('expires_at')
|
@error('expires_at')
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<h1>Products</h1>
|
<h1>Vouchers</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<ol class="breadcrumb float-sm-right">
|
<ol class="breadcrumb float-sm-right">
|
||||||
<li class="breadcrumb-item"><a href="{{route('home')}}">Dashboard</a></li>
|
<li class="breadcrumb-item"><a href="{{route('home')}}">Dashboard</a></li>
|
||||||
<li class="breadcrumb-item"><a class="text-muted"
|
<li class="breadcrumb-item"><a class="text-muted"
|
||||||
href="{{route('admin.products.index')}}">Products</a></li>
|
href="{{route('admin.vouchers.index')}}">Vouchers</a></li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,8 +28,8 @@
|
||||||
|
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
<h5 class="card-title"><i class="fas fa-sliders-h mr-2"></i>Products</h5>
|
<h5 class="card-title"><i class="fas fa-money-check-alt mr-2"></i>Vouchers</h5>
|
||||||
<a href="{{route('admin.products.create')}}" class="btn btn-sm btn-primary"><i
|
<a href="{{route('admin.vouchers.create')}}" class="btn btn-sm btn-primary"><i
|
||||||
class="fas fa-plus mr-1"></i>Create new</a>
|
class="fas fa-plus mr-1"></i>Create new</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,19 +39,12 @@
|
||||||
<table id="datatable" class="table table-striped">
|
<table id="datatable" class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Active</th>
|
<th>Status</th>
|
||||||
<th>Name</th>
|
<th>Code</th>
|
||||||
<th>Price</th>
|
<th>Memo</th>
|
||||||
<th>Memory</th>
|
<th>Credits</th>
|
||||||
<th>Cpu</th>
|
<th>Used / Uses</th>
|
||||||
<th>Swap</th>
|
<th>Expires</th>
|
||||||
<th>Disk</th>
|
|
||||||
<th>IO</th>
|
|
||||||
<th>Databases</th>
|
|
||||||
<th>Backups</th>
|
|
||||||
<th>Allocations</th>
|
|
||||||
<th>Servers</th>
|
|
||||||
<th>Created at</th>
|
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -79,21 +72,14 @@
|
||||||
processing: true,
|
processing: true,
|
||||||
serverSide: true,
|
serverSide: true,
|
||||||
stateSave: true,
|
stateSave: true,
|
||||||
ajax: "{{route('admin.products.datatable')}}",
|
ajax: "{{route('admin.vouchers.datatable')}}",
|
||||||
columns: [
|
columns: [
|
||||||
{data: 'disabled'},
|
{data: 'status'},
|
||||||
{data: 'name'},
|
{data: 'code'},
|
||||||
{data: 'price'},
|
{data: 'memo'},
|
||||||
{data: 'memory'},
|
{data: 'credits'},
|
||||||
{data: 'cpu'},
|
{data: 'uses'},
|
||||||
{data: 'swap'},
|
{data: 'expires_at'},
|
||||||
{data: 'disk'},
|
|
||||||
{data: 'io'},
|
|
||||||
{data: 'databases'},
|
|
||||||
{data: 'backups'},
|
|
||||||
{data: 'allocations'},
|
|
||||||
{data: 'servers', sortable: false},
|
|
||||||
{data: 'created_at'},
|
|
||||||
{data: 'actions', sortable: false},
|
{data: 'actions', sortable: false},
|
||||||
],
|
],
|
||||||
fnDrawCallback: function( oSettings ) {
|
fnDrawCallback: function( oSettings ) {
|
||||||
|
|
|
@ -96,6 +96,10 @@
|
||||||
Log back in
|
Log back in
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
|
<a class="dropdown-item" data-toggle="modal" data-target="#redeemVoucherModal" href="javascript:void(0)">
|
||||||
|
<i class="fas fa-money-check-alt fa-sm fa-fw mr-2 text-gray-400"></i>
|
||||||
|
Redeem code
|
||||||
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<form method="post" action="{{route('logout')}}">
|
<form method="post" action="{{route('logout')}}">
|
||||||
@csrf
|
@csrf
|
||||||
|
@ -253,6 +257,14 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="{{route('admin.vouchers.index')}}"
|
||||||
|
class="nav-link @if(Request::routeIs('admin.vouchers.*')) active @endif">
|
||||||
|
<i class="nav-icon fas fa-money-check-alt"></i>
|
||||||
|
<p>Vouchers</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="{{route('admin.usefullinks.index')}}"
|
<a href="{{route('admin.usefullinks.index')}}"
|
||||||
class="nav-link @if(Request::routeIs('admin.usefullinks.*')) active @endif">
|
class="nav-link @if(Request::routeIs('admin.usefullinks.*')) active @endif">
|
||||||
|
@ -261,7 +273,6 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -289,6 +300,8 @@
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@yield('content')
|
@yield('content')
|
||||||
|
|
||||||
|
@include('models.redeem_voucher_modal')
|
||||||
</div>
|
</div>
|
||||||
<!-- /.content-wrapper -->
|
<!-- /.content-wrapper -->
|
||||||
<footer class="main-footer">
|
<footer class="main-footer">
|
||||||
|
@ -319,6 +332,12 @@
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('[data-toggle="popover"]').popover();
|
$('[data-toggle="popover"]').popover();
|
||||||
|
|
||||||
|
$.ajaxSetup({
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
<!-- Button to Open the Modal -->
|
||||||
|
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#redeemVoucherModal">
|
||||||
|
Open modal
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- The Modal -->
|
||||||
|
<div class="modal fade" id="redeemVoucherModal">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
|
||||||
|
<!-- Modal Header -->
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title">Redeem voucher code</h4>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal body -->
|
||||||
|
<div class="modal-body">
|
||||||
|
<form>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="code">Code</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<div class="input-group-text">
|
||||||
|
<i class="fas fa-money-check-alt"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input id="code" name="code" placeholder="SUMMER" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal footer -->
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
|
||||||
|
<button name="submit" type="button" class="btn btn-primary">Redeem</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function validateCode(){
|
||||||
|
$.ajax({
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -12,6 +12,7 @@ use App\Http\Controllers\Admin\ServerController as AdminServerController;
|
||||||
use App\Http\Controllers\Admin\SettingsController;
|
use App\Http\Controllers\Admin\SettingsController;
|
||||||
use App\Http\Controllers\Admin\UsefulLinkController;
|
use App\Http\Controllers\Admin\UsefulLinkController;
|
||||||
use App\Http\Controllers\Admin\UserController;
|
use App\Http\Controllers\Admin\UserController;
|
||||||
|
use App\Http\Controllers\Admin\VoucherController;
|
||||||
use App\Http\Controllers\Auth\SocialiteController;
|
use App\Http\Controllers\Auth\SocialiteController;
|
||||||
use App\Http\Controllers\HomeController;
|
use App\Http\Controllers\HomeController;
|
||||||
use App\Http\Controllers\NotificationController;
|
use App\Http\Controllers\NotificationController;
|
||||||
|
@ -110,6 +111,9 @@ Route::middleware('auth')->group(function () {
|
||||||
Route::get('usefullinks/datatable', [UsefulLinkController::class, 'datatable'])->name('usefullinks.datatable');
|
Route::get('usefullinks/datatable', [UsefulLinkController::class, 'datatable'])->name('usefullinks.datatable');
|
||||||
Route::resource('usefullinks', UsefulLinkController::class);
|
Route::resource('usefullinks', UsefulLinkController::class);
|
||||||
|
|
||||||
|
Route::get('vouchers/datatable', [VoucherController::class, 'datatable'])->name('vouchers.datatable');
|
||||||
|
Route::resource('vouchers', VoucherController::class);
|
||||||
|
|
||||||
Route::get('api/datatable', [ApplicationApiController::class, 'datatable'])->name('api.datatable');
|
Route::get('api/datatable', [ApplicationApiController::class, 'datatable'])->name('api.datatable');
|
||||||
Route::resource('api', ApplicationApiController::class)->parameters([
|
Route::resource('api', ApplicationApiController::class)->parameters([
|
||||||
'api' => 'applicationApi',
|
'api' => 'applicationApi',
|
||||||
|
|
Loading…
Reference in a new issue