Merge branch 'trunk'

This commit is contained in:
Vincent BRIDIER 2023-10-06 13:02:34 +02:00
commit 41f51b1718
No known key found for this signature in database
GPG key ID: 8571BFA20420D512
19 changed files with 1270 additions and 518 deletions

View file

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Brands\GetBrandUrlsRequest;
use App\Http\Requests\Bo\Brands\StoreBrandRequest;
use App\Http\Requests\Bo\Brands\UpdateBrandRequest;
use App\Models\Brand;
@ -124,6 +125,7 @@ class BrandController extends Controller
));
});
}
/**
* Remove the specified resource from storage.
*
@ -148,4 +150,21 @@ class BrandController extends Controller
['model' => Str::singular(trans('models.classes.brands'))]
));
}
/**
* Get urls from a given brand.
*
* @param \App\Http\Requests\Bo\Brands\GetBrandUrlsRequest $request
* @param \App\Models\Brand $brand
* @return \Illuminate\Http\JsonResponse
*/
public function getUrls(GetBrandUrlsRequest $request, Brand $brand)
{
if (!$request->wantsJson()) {
return abort(404);
}
return response()
->json($brand->urls);
}
}

View file

@ -0,0 +1,333 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\StatsRequest;
use App\Models\Brand;
use App\Models\Url;
use App\Models\UrlStats;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Colors\RandomColor;
class StatsController extends Controller
{
/** @var array Colors used in charts */
private $colors = [];
/**
* Stats Page
*
* @param \App\Http\Requests\Bo\StatsRequest $request
* @return \Illuminate\Contracts\View\View
*/
public function index(StatsRequest $request)
{
$brandModels = Brand::all();
$chart = null;
$start = $request->start ? Carbon::parse($request->start) : null;
$end = $request->end ? Carbon::parse($request->end) : null;
$period = $request->period;
if ($request->post()) {
$periodInterval = CarbonPeriod::create($start, $end);
$chart = $this->getChart($request);
} //end if
return view('bo.pages.stats', compact('brandModels', 'chart', 'start', 'end'));
}
/**
* Get a chart from ChartJs.
*
* @param \Illuminate\Http\Request $request
* @return object
*/
private function getChart(Request $request)
{
$period = $request->period;
$periodInterval = $this->getDateInterval($request->start, $request->end, $request->period);
foreach ($periodInterval as $date) {
$labels[] = $this->getChartLabels($date, $request->period);
}
if (!$request->brand) {
$datasets = $this->getGlobalDatas($periodInterval, Brand::all(), $period);
} elseif (!$request->url) {
$datasets = $this->getBrandDatas($periodInterval, Brand::find($request->brand), $period);
} else {
$datasets = $this->getUrlDatas($periodInterval, Url::find($request->url), $period);
}
if (count(Arr::first($datasets)['data']) > 1) {
$type = 'line';
} else {
$type = 'bar';
}
return app()->chartjs
->name('stats')
->type($type)
->labels($labels)
->datasets($datasets)
->optionsRaw($options ?? "{}");
}
/**
* Get datas for all brands.
*
* @param \Carbon\CarbonPeriod $periodInterval
* @param \Illuminate\Database\Eloquent\Collection $brandModels
* @param string $period
* @return array
*/
private function getGlobalDatas(
CarbonPeriod $periodInterval,
\Illuminate\Database\Eloquent\Collection $brandModels,
string $period = "day"
) {
foreach ($brandModels as $brand) {
foreach ($periodInterval as $date) {
switch ($period) {
case 'day':
$dailyStats = UrlStats::where('date', $date)
->whereIn('url_id', $brand->urls->pluck('id'))
->get();
break;
case 'week':
$dailyStats = UrlStats::whereIn(
'date',
CarbonPeriod::create(
$date->startOfWeek()->format('Y-m-d'),
$date->endOfWeek()->format('Y-m-d')
)->toArray()
)->whereIn('url_id', $brand->urls->pluck('id'))
->get();
break;
case 'month':
$dailyStats = UrlStats::whereIn(
'date',
CarbonPeriod::create(
$date->startOfMonth()->format('Y-m-d'),
$date->endOfMonth()->format('Y-m-d')
)->toArray()
)->whereIn('url_id', $brand->urls->pluck('id'))
->get();
break;
} //end switch
$data[$brand->id][] = $dailyStats->sum('calls');
} //end foreach
$color = $this->getUniqueColor();
$datasets[] = [
'label' => $brand->name,
'backgroundColor' => $color,
'borderColor' => $color,
"pointBorderColor" => $color,
"pointBackgroundColor" => $color,
'data' => $data[$brand->id],
'lineTension' => 0.4,
];
} //end foreach
return $datasets;
}
/**
* Get a chart for all urls of a given brand.
*
* @param \Carbon\CarbonPeriod $periodInterval
* @param \App\Models\Brand $brand
* @param string $period
* @return object
*/
private function getBrandDatas(
CarbonPeriod $periodInterval,
\App\Models\Brand $brand,
string $period = "day"
) {
foreach ($brand->urls as $url) {
foreach ($periodInterval as $date) {
switch ($period) {
case 'day':
$dailyStats = UrlStats::where('date', $date)
->where('url_id', $url->id)
->get();
break;
case 'week':
$dailyStats = UrlStats::whereIn(
'date',
CarbonPeriod::create(
$date->startOfWeek()->format('Y-m-d'),
$date->endOfWeek()->format('Y-m-d')
)->toArray()
)->where('url_id', $url->id)
->get();
break;
case 'month':
$dailyStats = UrlStats::whereIn(
'date',
CarbonPeriod::create(
$date->startOfMonth()->format('Y-m-d'),
$date->endOfMonth()->format('Y-m-d')
)->toArray()
)->where('url_id', $url->id)
->get();
break;
} //end switch
$data[$url->id][] = $dailyStats->sum('calls');
} //end foreach
$color = $this->getUniqueColor();
$datasets[] = [
'label' => $url->value,
'backgroundColor' => $color,
'borderColor' => $color,
"pointBorderColor" => $color,
"pointBackgroundColor" => $color,
'data' => $data[$url->id],
'lineTension' => 0.4,
];
} //end foreach
return $datasets;
}
/**
* Get a chart for a given url.
*
* @param \Carbon\CarbonPeriod $periodInterval
* @param \App\Models\Url $url
* @param string $period
* @return object
*/
private function getUrlDatas(
CarbonPeriod $periodInterval,
\App\Models\Url $url,
string $period = 'day'
) {
foreach ($periodInterval as $date) {
switch ($period) {
case 'day':
$dailyStats = UrlStats::where('date', $date)
->where('url_id', $url->id)
->get();
break;
case 'week':
$dailyStats = UrlStats::whereIn(
'date',
CarbonPeriod::create(
$date->startOfWeek()->format('Y-m-d'),
$date->endOfWeek()->format('Y-m-d')
)->toArray()
)->where('url_id', $url->id)
->get();
break;
case 'month':
$dailyStats = UrlStats::whereIn(
'date',
CarbonPeriod::create(
$date->startOfMonth()->format('Y-m-d'),
$date->endOfMonth()->format('Y-m-d')
)->toArray()
)->where('url_id', $url->id)
->get();
break;
} //end switch
$data[$url->id][] = $dailyStats->sum('calls');
} //end foreach
$color = $this->getUniqueColor();
$datasets[] = [
'label' => $url->value,
'backgroundColor' => $color,
'borderColor' => $color,
"pointBorderColor" => $color,
"pointBackgroundColor" => $color,
'data' => $data[$url->id],
'lineTension' => 0.4,
];
return $datasets;
}
/**
* Get the CarbonPeriod for the given period.
*
* @param string $start
* @param string $end
* @param string $period Can be day|week|month.
* @return \Carbon\CarbonPeriod
*/
private function getDateInterval(string $start, string $end, string $period)
{
switch ($period) {
case 'day':
$periodInterval = CarbonPeriod::create($start, $end);
break;
case 'week':
$periodInterval = CarbonPeriod::create(
Carbon::parse($start)->startOfWeek(),
Carbon::parse($end)->endOfWeek(),
'1 week'
);
break;
case 'month':
$periodInterval = CarbonPeriod::create(
Carbon::parse($start)->startOfMonth(),
Carbon::parse($end)->endOfMonth(),
'1 month'
);
break;
default:
$periodInterval = CarbonPeriod::create($start, $end);
} //end switch
return $periodInterval;
}
/**
* Get labels for charts.
*
* @param Carbon\Carbon $date
* @param string $period Can be day|week|month.
* @return string
*/
private function getChartLabels(Carbon $date, string $period)
{
$labels = [];
if ($period === "day") {
$labels = array_merge($labels, [$date->format('d-m-Y')]);
}
if ($period === "week") {
$labels = array_unique(array_merge($labels, [sprintf(
'Du %s au %s',
$date->startOfWeek()->format('Y-m-d'),
$date->endOfWeek()->format('Y-m-d')
)]));
}
if ($period === "month") {
$labels = array_unique(array_merge($labels, [Str::ucfirst($date->monthName)]));
}
return $labels;
}
/**
* getUniqueColor
*
* @return string
*/
private function getUniqueColor()
{
$color = RandomColor::one();
if (in_array($color, $this->colors)) {
return $this->getUniqueColor();
}
$this->colors[] = $color;
return $color;
}
}

View file

@ -30,7 +30,8 @@ class UrlController extends Controller
$urls,
$request->search,
null,
'name',
'key',
'value'
);
}

View file

@ -0,0 +1,28 @@
<?php
namespace App\Http\Requests\Bo\Brands;
use Illuminate\Foundation\Http\FormRequest;
class GetBrandUrlsRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return auth('backend')->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [];
}
}

View file

@ -0,0 +1,69 @@
<?php
namespace App\Http\Requests\Bo;
use App\Models\Brand;
use App\Models\Url;
use Carbon\Carbon;
use Illuminate\Foundation\Http\FormRequest;
class StatsRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$this->merge([
// Reset brand and url if no value is selected.
'url' => Url::find($this->url) ? $this->url : null,
'brand' => Brand::find($this->brand) ? $this->brand : null,
// End date can't be after today.
'end' => Carbon::parse($this->end) > now() ? now()->toDateString() : $this->end,
]);
if ($this->period === 'week') {
$this->merge([
'start' => Carbon::parse($this->start)->startOfWeek()->toDateString(),
'end' => Carbon::parse($this->end)->endOfWeek()->toDateString(),
]);
}
if ($this->period === 'month') {
$this->merge([
'start' => Carbon::parse($this->start)->startOfMonth()->toDateString(),
'end' => Carbon::parse($this->end)->endOfMonth()->toDateString(),
]);
}
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
if (request()->post()) {
return [
'period' => 'required|string|in:day,week,month',
'start' => 'required|date|date_format:Y-m-d|before_or_equal:today|after_or_equal:'
. Carbon::parse($this->end)->modify('-1 year'),
'end' => 'required|date|date_format:Y-m-d|after_or_equal:start',
'brand' => 'nullable|integer|exists:App\Models\Brand,id',
'url' => 'nullable|integer|exists:App\Models\Url,id'
];
}
return [];
}
}

View file

@ -8,6 +8,7 @@
"php": "^7.3|^8.0",
"diglactic/laravel-breadcrumbs": "^6.1",
"fruitcake/laravel-cors": "^2.0",
"fx3costa/laravelchartjs": "^3.0",
"guzzlehttp/guzzle": "^7.0.1",
"kwaadpepper/enum": "^2.1",
"kwaadpepper/image-resizer": "^0.1.2",
@ -16,6 +17,7 @@
"laravel/ui": "^3.4",
"ldc/web-admin-secure-laravel": "^1.0",
"mews/purifier": "^3.3",
"mistic100/randomcolor": "^1.0",
"sentry/sentry-laravel": "^3.2",
"spatie/laravel-mix-preload": "^1.3"
},

102
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "a016428bf29d21ef8e8f541266808f09",
"content-hash": "c39af8f51ec628f1255518fec5ae3659",
"packages": [
{
"name": "asm89/stack-cors",
@ -745,6 +745,62 @@
"abandoned": true,
"time": "2022-02-23T14:25:13+00:00"
},
{
"name": "fx3costa/laravelchartjs",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/fxcosta/laravel-chartjs.git",
"reference": "255154a4a6b57fb146eba4fdedcef4d1fe075e68"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fxcosta/laravel-chartjs/zipball/255154a4a6b57fb146eba4fdedcef4d1fe075e68",
"reference": "255154a4a6b57fb146eba4fdedcef4d1fe075e68",
"shasum": ""
},
"require": {
"illuminate/support": "^5.1|^6.0|^7.0|^8.0|^9.0|^10.0",
"php": ">=5.6.4"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Fx3costa\\LaravelChartJs\\Providers\\ChartjsServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Fx3costa\\LaravelChartJs\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Felix",
"email": "fx3costa@gmail.com"
}
],
"description": "Simple package to facilitate and automate the use of charts in Laravel 5.x using Chartjs v2 library",
"keywords": [
"chart",
"chartjs",
"fx3costa",
"graphics",
"laravel5",
"reports"
],
"support": {
"issues": "https://github.com/fxcosta/laravel-chartjs/issues",
"source": "https://github.com/fxcosta/laravel-chartjs/tree/3.0.0"
},
"time": "2023-02-23T12:23:49+00:00"
},
{
"name": "graham-campbell/result-type",
"version": "v1.1.1",
@ -2279,6 +2335,50 @@
},
"time": "2022-07-20T12:14:06+00:00"
},
{
"name": "mistic100/randomcolor",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/mistic100/RandomColor.php.git",
"reference": "527635e9d632ea216c91baf1ffb51f4c81d763de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mistic100/RandomColor.php/zipball/527635e9d632ea216c91baf1ffb51f4c81d763de",
"reference": "527635e9d632ea216c91baf1ffb51f4c81d763de",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-4": {
"Colors\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Damien \"Mistic\" Sorel",
"email": "contact@git.strangeplanet.fr",
"homepage": "http://www.strangeplanet.fr"
}
],
"description": "Generate attractive random colors",
"homepage": "https://github.com/mistic100/RandomColor.php",
"keywords": [
"color",
"generator",
"random"
],
"support": {
"issues": "https://github.com/mistic100/RandomColor.php/issues",
"source": "https://github.com/mistic100/RandomColor.php/tree/1.0.6"
},
"time": "2022-10-13T11:40:28+00:00"
},
{
"name": "monolog/monolog",
"version": "2.9.1",

View file

@ -167,6 +167,8 @@ return [
* Package Service Providers...
*/
Fx3costa\LaravelChartJs\Providers\ChartjsServiceProvider::class,
/*
* Application Service Providers...
*/
@ -230,6 +232,8 @@ return [
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Carbon' => Illuminate\Support\Carbon::class,
],

975
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,7 @@
"@rushstack/eslint-patch": "^1.1.4",
"@sipec/vue3-tags-input": "^3.0.4",
"@types/bootstrap": "^5.2.6",
"@types/chart.js": "^2.9.38",
"@types/cropperjs": "^1.3.0",
"@types/toastify-js": "^1.11.1",
"@types/webpack-env": "^1.18.0",
@ -30,6 +31,7 @@
"@vue/eslint-config-typescript": "^11.0.0",
"axios": "^0.21",
"bootstrap": "^5.2.3",
"chart.js": "^2.0.0",
"clean-webpack-plugin": "^4.0.0",
"cropperjs": "^1.5.12",
"eslint": "^8.23.0",
@ -42,12 +44,13 @@
"laravel-mix-stylelint": "^1.0.0",
"postcss": "^8.1.14",
"prettier": "^2.7.1",
"qr-code-styling": "^1.6.0-rc.1",
"resolve-url-loader": "^5.0.0",
"sass": "^1.54.8",
"sass-loader": "^12.6.0",
"slugify": "^1.6.5",
"stylelint": "^14.11.0",
"stylelint-config-idiomatic-order": "^8.1.0",
"stylelint-config-idiomatic-order": "^9.0.0",
"stylelint-config-sass-guidelines": "^9.0.1",
"stylelint-config-standard-scss": "^6.1.0",
"stylelint-webpack-plugin": "^3.3.0",
@ -59,8 +62,5 @@
"vue": "^3.2.38",
"vue-eslint-parser": "^9.1.0",
"vue-loader": "^16.8.3"
},
"dependencies": {
"qr-code-styling": "^1.6.0-rc.1"
}
}

View file

@ -11,3 +11,6 @@
@import "./base/fonts";
@import "./base/classes";
@import "./base/common";
// * PAGES
@import "./pages/stats";

View file

@ -0,0 +1 @@
// Empty.

View file

@ -160,9 +160,9 @@ p {
padding: 0;
border-width: 1px;
border-color: color.scale($body-bg, $lightness: -30%);
border-radius: 2px;
margin: 0 auto;
background-color: $body-bg;
border-radius: 2px;
box-shadow: 0 2px 0 rgb(0 0 150 / 2.5%), 2px 4px 0 rgb(0 0 150 / 1.5%);
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;

View file

@ -1,5 +1,6 @@
// UTILITIES
import "./utilities/bootstrap";
import "./utilities/chartjs";
import "./utilities/fontawesome";
// MODULES
@ -8,3 +9,4 @@ import "./modules/sweetalert";
// CUSTOM
import "./bo/common";
import "./bo/vue-bo";

View file

@ -1,6 +1,7 @@
export {};
import { AxiosStatic } from "axios";
export { };
import type VueTagsInput from "@sipec/vue3-tags-input";
import { AxiosStatic } from "axios";
import { Chart } from "chart.js";
// * Enum
interface EnumInterface {
@ -72,6 +73,7 @@ declare global {
interface Window {
axios: AxiosStatic;
Chart: typeof Chart;
Swal: Function;
vueDebug: boolean | undefined;
__SYSTEM: {

View file

@ -0,0 +1,2 @@
import { Chart } from "chart.js";
window.Chart = Chart;

View file

@ -8,6 +8,14 @@
{{ __('Dashboard') }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if(request()->routeIs('bo.stats.*')) active @endif"
href="{{ route('bo.stats.index') }}"
title="{{ __('Accéder aux statistiques') }}"
data-bs-toggle="tooltip">
{{ __('Stats') }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if(request()->routeIs('bo.brands.index')) active @endif"
href="{{ route('bo.brands.index') }}"

View file

@ -0,0 +1,171 @@
@extends('bo.layout')
@section('title', __('Accueil'))
@section('description', __('Description site'))
@section('breadcrumb', 'no')
@section('content')
<div class="container">
<div class="row">
<div class="col">
<div class="card" id="main-card">
<div class="card-header">
<div class="row">
<div class="d-flex justify-content-between flex-md-nowrap align-items-center flex-wrap pb-2 pt-3">
<div class="d-flex align-items-end">
<img class="d-none d-print-block me-2" src="{{ mix('assets/images/logo.png', 'build') }}"
style="height: 2rem">
<h1 class="fs-2 mb-0"><span class="fw-bold">
{{ __('Statistiques') }}
</h1>
@if (!empty($start) && !empty($end))
<p class="fw-bold mb-0 ms-4">
{{ __('Période du') }} {{ $start->isoFormat('ll') }} - {{ $end->isoFormat('ll') }}
</p>
@endif
</div>
</div>
</div>
</div>
<div class="card-body">
{{-- Top-bar --}}
<div class="row justify-content-end d-print-none">
<div class="col-12">
<form action="{{ url()->current() }}" method="POST">
@csrf
<div class="row">
<div class="col-sm-12 col-xl-3 w-auto">
<div class="input-group mb-3" id="matomo-options-bar">
<div class="form-check">
<label class="form-check-label" for="period-day">{{ __('Jour') }}</label>
<input class="form-check-input" id="period-day" name="period" type="radio" value="day"
@if (request('period') === 'day' || empty(request('period'))) checked @endif>
</div>
<div class="form-check ms-2">
<label class="form-check-label" for="period-week">{{ __('Semaine') }}</label>
<input class="form-check-input" id="period-week" name="period" type="radio"
value="week" @if (request('period') === 'week') checked @endif>
</div>
<div class="form-check ms-2">
<label class="form-check-label" for="period-month">{{ __('Mois') }}</label>
<input class="form-check-input" id="period-month" name="period" type="radio"
value="month" @if (request('period') === 'month') checked @endif>
</div>
</div>
</div>
</div>
<div class="input-group mb-3">
<span class="input-group-text">{{ __('Début') }}</span>
<input class="form-control date start" name="start" type="date"
value="{{ !empty($start)? $start->format('Y-m-d'): Carbon::now()->startOfMonth()->format('Y-m-d') }}"
required>
<span class="input-group-text">{{ __('Fin') }}</span>
<input class="form-control date end" name="end" type="date"
value="{{ !empty($end) ? $end->format('Y-m-d') : Carbon::now()->format('Y-m-d') }}" required>
<button class="btn btn-primary" type="submit">
{{ __('Visualiser') }}
</button>
</div>
<div class="row">
<div class="col-5">
<div class="input-group mb-3">
<label class="input-group-text" for="inputGroupBrands">{{ __('Marque') }}</label>
<select class="form-select" id="inputGroupBrands" name="brand">
<option id="baseBrandOption" selected>{{ __('Sélectionnez une marque') }}</option>
@foreach ($brandModels as $brand)
<option value="{{ $brand->id }}" @if ($brand->id == request()->brand) selected @endif>
{{ $brand->name }}
</option>
@endforeach
</select>
</div>
</div>
<div class="col-7 d-none" id="urlSelect">
<div class="input-group mb-3">
<label class="input-group-text" for="inputGroupUrls">{{ __('URL') }}</label>
<select class="form-select" id="inputGroupUrls" name="url">
<option selected>{{ __('Sélectionnez une url') }}</option>
@if (\App\Models\Brand::find(request()->brand))
@foreach (\App\Models\Brand::find(request()->brand)->urls as $url)
<option value="{{ $url->id }}"
@if ($url->id == request()->url) selected @endif>
{{ $url->value }}
</option>
@endforeach
@endif
</select>
</div>
</div>
</div>
</form>
</div>
</div>
{{-- Stats card --}}
@if ($chart)
<div class="card mb-3 mt-3">
<div class="card-body">
<div class="row justify-content-center">
<div class="col-10 chart">
{!! $chart->render() !!}
</div>
</div>
</div>
</div>
@endif
</div>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script nonce="{{ $nonce }}">
document.addEventListener('DOMContentLoaded', () => {
// Allow url selection if a brand is selected.
const brandInput = document.getElementById('inputGroupBrands');
const urlInput = document.getElementById('urlSelect');
let urls = [];
if (brandInput.value !== document.getElementById('baseBrandOption').textContent) {
urlInput.classList.remove('d-none');
}
brandInput.addEventListener('change', (e) => {
if (brandInput.value !== document.getElementById('baseBrandOption').textContent) {
urlInput.classList.remove('d-none');
let fetchUrl = "{{ route('bo.brands.geturls', ':id') }}"
fetchUrl = fetchUrl.replace(':id', brandInput.value);
axios
.get(fetchUrl)
.then((response) => {
urls = response.data;
displayUrlInput(urls);
})
} else {
urlInput.classList.add('d-none');
}
})
})
function displayUrlInput(urls) {
const urlSelectInput = document.getElementById('inputGroupUrls');
// Empty select input.
for (let i = urlSelectInput.options.length - 1; i >= 0; i--) {
urlSelectInput.remove(i);
}
// Set default option.
let defaultOption = new Option();
defaultOption.label = 'Sélectionnez une url';
urlSelectInput.appendChild(defaultOption);
// Set an option for each url.
for (let url of urls) {
let option = new Option();
option.label = url.value;
option.value = url.id;
urlSelectInput.appendChild(option);
}
}
</script>
@endpush

View file

@ -2,27 +2,41 @@
use App\Http\Controllers\Bo\BrandController;
use App\Http\Controllers\Bo\DashboardController;
use App\Http\Controllers\Bo\StatsController;
use App\Http\Controllers\Bo\UrlController;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
Route::prefix('bo')->name('bo.')->middleware(['admin-secure', 'throttle:credentials'])->group(function () {
Route::namespace('\App\Http\Controllers\Bo')->group(function () {
Auth::routes([
'login' => true,
'logout' => true,
'reset' => false,
'register' => false,
'confirm' => false,
'verify' => false
]);
});
Route::prefix('bo')
->name('bo.')
->middleware(['admin-secure', 'throttle:credentials'])
->group(function () {
// Authenticate routes.
Route::namespace('\App\Http\Controllers\Bo')
->group(function () {
Auth::routes([
'login' => true,
'logout' => true,
'reset' => false,
'register' => false,
'confirm' => false,
'verify' => false
]);
});
Route::middleware('auth:backend')->group(function () {
Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
// Brands routes.
Route::resource('/brands', BrandController::class);
// Urls routes.
Route::resource('/urls', UrlController::class);
Route::middleware('auth:backend')
->group(function () {
Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
// Stats routes.
Route::get('/stats', [StatsController::class, 'index'])->name('stats.index');
Route::post('/stats', [StatsController::class, 'index'])->name('stats.show');
// Brands routes.
Route::resource('/brands', BrandController::class);
Route::get('/brand/{brand}/url', [BrandController::class, 'getUrls'])->name('brands.geturls');
// Urls routes.
Route::resource('/urls', UrlController::class);
});
});
});