add hot news on home page
This commit is contained in:
parent
50f6f68f79
commit
d18427f299
15 changed files with 222 additions and 50 deletions
|
|
@ -5,9 +5,11 @@ namespace App\Http\Controllers\Bo;
|
|||
use App\Enums\Settings\SettingsType;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\GeneralSettings\UpdateGeneralSettingRequest;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Models\GeneralSetting;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
|
|
@ -80,7 +82,20 @@ class GeneralSettingController extends Controller
|
|||
GeneralSetting $general_setting
|
||||
): \Illuminate\Http\RedirectResponse {
|
||||
return DB::transaction(function () use ($request, $general_setting) {
|
||||
$general_setting->fill($request->only('value'));
|
||||
if ($general_setting->type === SettingsType::hotNews) {
|
||||
collect($request->only(['value->picture', 'value->text', 'value->picture_alt', 'value->picture_title']))
|
||||
->each(fn (string|\Illuminate\Http\UploadedFile $value, string $attribute) =>
|
||||
$general_setting->setAttribute(
|
||||
$attribute,
|
||||
$value instanceof \Illuminate\Http\UploadedFile ?
|
||||
FileStorageHelper::storeFile($general_setting, $value, true):
|
||||
$value
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$general_setting->fill($request->only('value'));
|
||||
}
|
||||
|
||||
if ($general_setting->saveOrFail()) {
|
||||
return redirect()->route('bo.general_settings.edit', $general_setting)
|
||||
->with('success', __('crud.messages.has_been_updated', [
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Enums\Settings\SettingsType;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Fo\SingleOptinRequest;
|
||||
use App\Models\DemarcheSlide;
|
||||
use App\Models\MainSlide;
|
||||
use App\Models\Product;
|
||||
use App\Models\GeneralSetting;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Vite;
|
||||
use LDC\LDCCRM\Enums\ApiError;
|
||||
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
||||
|
|
@ -26,6 +29,7 @@ class HomeController extends Controller
|
|||
->with('approach')->get();
|
||||
$demarcheSlideModels = DemarcheSlide::query()->where('published', true)->orderBy('order', 'ASC')->get();
|
||||
$productViews = Product::getProductsViewsByRange();
|
||||
$hotNewsSettings = GeneralSetting::query()->where('type', SettingsType::hotNews)->first();
|
||||
// FIXME: replace 'for loop' by eloquent orm on news publicated.
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$newsModels[] = (object)['title' => "lorem ipsum"];
|
||||
|
|
@ -47,7 +51,8 @@ class HomeController extends Controller
|
|||
'demarcheSlideModels',
|
||||
'productViews',
|
||||
'newsModels',
|
||||
'recipeModels'
|
||||
'recipeModels',
|
||||
'hotNewsSettings'
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -76,4 +81,15 @@ class HomeController extends Controller
|
|||
return \response(trans('Une erreur est survenue, merci de réessayer ultérieurement'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function updateHotNewsSatus(): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
Cache::remember("hotNewsIsDisplayed", 60 * 60 * 24, fn() => true);
|
||||
return response()->json();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,12 +33,10 @@ class UpdateGeneralSettingRequest extends FormRequest
|
|||
if ($generalSettingModel->type === SettingsType::hotNews) {
|
||||
$this->mergePicture('picture');
|
||||
$this->merge([
|
||||
'value' => [
|
||||
'picture_alt' => $this->input('picture_alt'),
|
||||
'picture_title' => $this->input('picture_title'),
|
||||
'picture' => $this->input('picture_title'),
|
||||
'text' => $this->input('text')
|
||||
]
|
||||
'value->picture' => $this->file('picture'),
|
||||
'value->text' => $this->input('text'),
|
||||
'value->picture_alt' => $this->input('picture_alt'),
|
||||
'value->picture_title' => $this->input('picture_title'),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
|
@ -64,7 +62,7 @@ class UpdateGeneralSettingRequest extends FormRequest
|
|||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 200, 150, 200, 150, false),
|
||||
$this->pictureRules('picture', 200, 100, 200, 100, false),
|
||||
);
|
||||
} else {
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class FileStorageHelper
|
|||
*/
|
||||
public static function storeFile(
|
||||
Model $model,
|
||||
$file,
|
||||
\Illuminate\Http\UploadedFile|\SplFileInfo|string|null $file,
|
||||
bool $slugify = false,
|
||||
string $filename = null,
|
||||
bool $private = false
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ use App\Lib\Link;
|
|||
use App\Traits\Models\IsCachedAsCollection;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
/**
|
||||
* @property-read \App\Enums\Settings\SettingsType $type Enum SettingsType.
|
||||
|
|
@ -49,7 +51,7 @@ class GeneralSetting extends Model
|
|||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'value',
|
||||
'value'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -71,15 +73,12 @@ class GeneralSetting extends Model
|
|||
protected static function booted(): void
|
||||
{
|
||||
static::creating(fn () => throw new \ErrorException('Not allowed to create an instance of this'));
|
||||
static::updating(function (self $model) {
|
||||
if ($model->type === SettingsType::hotNews) {
|
||||
// @phpstan-ignore-next-line
|
||||
$model->value = FileStorageHelper::storeFile($model, $model->value['picture'], true);
|
||||
}
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
if ($model->type === SettingsType::hotNews) {
|
||||
FileStorageHelper::removeOldFile($model, $model->value['picture']);
|
||||
FileStorageHelper::removeOldFiles(
|
||||
Arr::wrap(Arr::get($model->getOriginal('value'), 'picture')),
|
||||
Arr::wrap($model->value['picture'])
|
||||
);
|
||||
}
|
||||
self::removeCached();
|
||||
});
|
||||
|
|
|
|||
BIN
resources/assets/images/home/hot-news-wood.png
Normal file
BIN
resources/assets/images/home/hot-news-wood.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 295 KiB |
|
|
@ -1,4 +1,42 @@
|
|||
#home {
|
||||
#hot-news-desktop{
|
||||
.wood-background{
|
||||
height: 22rem;
|
||||
background-image: url('@/images/home/hot-news-wood.png');
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.hot-news-position{
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
top: -7%;
|
||||
right: 13%;
|
||||
}
|
||||
}
|
||||
|
||||
#hot-news{
|
||||
transition: .3s;
|
||||
|
||||
hr {
|
||||
border-top: 2px dashed;
|
||||
}
|
||||
|
||||
&.hot-news-hide {
|
||||
transform: translate(100%, -50%) !important;
|
||||
}
|
||||
|
||||
&-loader {
|
||||
opacity: 0;
|
||||
transition: .3s;
|
||||
visibility: hidden;
|
||||
|
||||
&.hot-news-loader-active {
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#main-slides {
|
||||
#swiper-main-slides {
|
||||
.swiper-background {
|
||||
|
|
|
|||
|
|
@ -12,3 +12,4 @@ import "./partials/layout";
|
|||
|
||||
// CUSTOM
|
||||
import "./base/common";
|
||||
import "./pages/home";
|
||||
|
|
|
|||
75
resources/ts/fo/pages/home.ts
Normal file
75
resources/ts/fo/pages/home.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import parseValidationErrors from "../../modules/parseLaravelErrorMessages";
|
||||
import route from "../../modules/route";
|
||||
import trans from "../../modules/trans";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
if (!document.querySelector("#home #hot-news")) {
|
||||
return;
|
||||
}
|
||||
// addClassIfViewportLessThan600();
|
||||
// * HOT NEWS
|
||||
const hotNews = document.getElementById("hot-news") as HTMLDivElement|null;
|
||||
const hotNewsLoader = hotNews?.querySelector("#hot-news-loader") as HTMLDivElement|null;
|
||||
const closeButton = hotNews?.querySelector("#close-hot-news") as HTMLDivElement|null;
|
||||
if (closeButton && hotNews && hotNewsLoader) {
|
||||
closeButton.addEventListener("click", function() {
|
||||
hotNews.setAttribute("inert", "true");
|
||||
hotNewsLoader?.classList.add("hot-news-loader-active");
|
||||
updateHotNewsCache(hotNews, hotNewsLoader);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/** Call ajax to update cache about hot news content */
|
||||
function updateHotNewsCache(hotNews: HTMLDivElement, hotNewsLoader: HTMLDivElement): void {
|
||||
// call ajax pour modif hot news status en false
|
||||
window.axios.post(getHomeHotNewsRoute()).then(function () {
|
||||
hotNews.classList.add("hot-news-hide");
|
||||
hotNews.removeAttribute("inert");
|
||||
setTimeout(() => {
|
||||
hotNewsLoader?.classList.remove("hot-news-loader-active");
|
||||
}, 300);
|
||||
}).catch((ajaxErrorHandler));
|
||||
}
|
||||
|
||||
/** Get home hot news route */
|
||||
function getHomeHotNewsRoute(): string {
|
||||
const homeRoute = route.methods.route("fo.home.hotnews");
|
||||
if (!homeRoute) {
|
||||
throw new Error("Undefined route fo.home.hotnews");
|
||||
}
|
||||
return homeRoute;
|
||||
}
|
||||
|
||||
/** Return error message after the ajax call */
|
||||
function ajaxErrorHandler(e: any): void {
|
||||
let message = trans.methods.__("Une erreur est survenue");
|
||||
if (e.response.status === 422) {
|
||||
message = parseValidationErrors.methods.parseValidationErrors(
|
||||
e.response?.data?.errors ?? {}
|
||||
) || message;
|
||||
if (window.vueDebug) {
|
||||
console.warn(e.response.data.errors);
|
||||
}
|
||||
} else if (e.response.status === 419) {
|
||||
console.log(trans.methods.__("Votre session a expiré, la page va être rechargée"));
|
||||
setTimeout(() => window.location.reload(), 2000);
|
||||
} else if (e.response.status === 403) {
|
||||
console.log(trans.methods.__("Vous n'êtes pas autorisé a effectuer cette action"));
|
||||
setTimeout(() => window.location.reload(), 2000);
|
||||
} else {
|
||||
if (window.vueDebug) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
// Définir une fonction pour ajouter une classe à une div si la taille du viewport est inférieure à 600px
|
||||
// function addClassIfViewportLessThan600() {
|
||||
// const viewportWidth = window.innerWidth;
|
||||
// const targetDiv = document.querySelector("#home #hot-news-desktop");
|
||||
// if (viewportWidth < 600 && targetDiv) {
|
||||
// targetDiv.classList.add("wood-background");
|
||||
// }
|
||||
// }
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
'id' => 'hotNewsPicture',
|
||||
'name' => 'picture',
|
||||
'width' => 200,
|
||||
'height' => 150,
|
||||
'height' => 100,
|
||||
'model' => null,
|
||||
'value' => $generalSettingModel->value['picture'],
|
||||
'required' => true,
|
||||
|
|
@ -109,16 +109,3 @@
|
|||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
{{--
|
||||
<div>
|
||||
{{ __($generalSettingModel->value['picture_alt']) }}
|
||||
</div>
|
||||
<div>
|
||||
{{ __($generalSettingModel->value['picture_title']) }}
|
||||
</div>
|
||||
<div>
|
||||
{{ __($generalSettingModel->value['picture']) }}
|
||||
</div>
|
||||
<div>
|
||||
{{ __($generalSettingModel->value['text']) }}
|
||||
</div> --}}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<div class="nav-collapse bg-light collapse shadow-sm" id="{{ $collapseId }}">
|
||||
<div class="row w-100 mb-xl-0 mx-auto mb-3">
|
||||
@include('fo.layouts.main-menu.partials.collapse-left', [
|
||||
'btnLabel' => str($menuNodeData->sub_label)->ucFirst(),
|
||||
'btnLabel' => str($menuNodeData->type->label())->ucFirst(),
|
||||
'btnLink' => route($menuNode->link->getRouteName()),
|
||||
])
|
||||
@include('fo.layouts.main-menu.partials.collapse-middle', [
|
||||
|
|
|
|||
|
|
@ -7,21 +7,19 @@
|
|||
@section('content')
|
||||
<section id="home">
|
||||
{{-- HOT NEWS --}}
|
||||
<div class="top-50 position-fixed z-3 end-0 bg-white">
|
||||
<div class="row p-4">
|
||||
<div class="col-6">
|
||||
<img src="" alt="">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row p-4">
|
||||
<div class="col-6">
|
||||
<img src="" alt="">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div @class([
|
||||
'top-50 end-0 translate-middle-y position-fixed z-3 bg-white d-none d-xl-block',
|
||||
'd-none' => cache()->get('hotNewsIsDisplayed')
|
||||
]) id="hot-news">
|
||||
<div id="hot-news-loader" class="bg-primary bg-opacity-50 position-absolute w-100 h-100 top-0 start-0 z-2">
|
||||
<div class="position-absolute start-50 top-50 translate-middle">
|
||||
<div class="spinner-border" role="status">
|
||||
<span class="visually-hidden">Chargement...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="close-hot-news" class="btn-close position-absolute start-0 top-0" aria-label="Close"></button>
|
||||
@include('fo.partials.hot-news')
|
||||
</div>
|
||||
{{-- MAIN SLIDES --}}
|
||||
@if ($mainSlideModels->isNotEmpty())
|
||||
|
|
@ -88,15 +86,25 @@
|
|||
<img src="{{ Vite::asset('resources/assets/images/common/arrow.svg') }}" title="{{ __('Navigation du slider (gauche)') }}"
|
||||
alt="{{ __('flèche vers la gauche') }}">
|
||||
</button>
|
||||
<button
|
||||
class="swiper-button swiper-button-next-custom swiper-main-slides-button-next rounded-circle z-1 mx-3 border-0 bg-white">
|
||||
<button class="swiper-button swiper-button-prev-custom swiper-main-slides-button-prev rounded-circle z-1 mx-3 border-0 bg-white">
|
||||
<img src="{{ Vite::asset('resources/assets/images/common/arrow.svg') }}" title="{{ __('Navigation du slider (gauche)') }}"
|
||||
alt="{{ __('flèche vers la gauche') }}">
|
||||
</button>
|
||||
<button class="swiper-button swiper-button-next-custom swiper-main-slides-button-next rounded-circle z-1 mx-3 border-0 bg-white">
|
||||
<img src="{{ Vite::asset('resources/assets/images/common/arrow.svg') }}" title="{{ __('Navigation du slider (droite)') }}"
|
||||
alt="{{ __('flèche vers la droite') }}">
|
||||
</button>
|
||||
<img class="d-none d-md-block w-100" src="{{ Vite::asset('resources/assets/images/home/bg-slider-wood.png') }}"
|
||||
title="{{ __('Image imitation bois') }}" alt="{{ __('Footer imitation bois du slider') }}">
|
||||
<img class="w-100 d-none d-xl-block" src="{{ Vite::asset('resources/assets/images/home/bg-slider-wood.png') }}"
|
||||
alt="{{ __('Footer imitation bois du slider') }}">
|
||||
</section>
|
||||
@endif
|
||||
{{-- HOT NEWS DESKTOP --}}
|
||||
<div id="hot-news-desktop" class="position-relative">
|
||||
<div class="wood-background w-100"></div>
|
||||
<div class="w-75 mx-auto d-block d-xl-none bg-white hot-news-position line-border-medium">
|
||||
@include('fo.partials.hot-news')
|
||||
</div>
|
||||
</div>
|
||||
{{-- RANGES/PRODUCTS --}}
|
||||
{{-- FIXME: uncomment when CRUD range is ready @if ($rangeModels->isNotEmpty()) --}}
|
||||
<section class="position-relative bg-light gx-0 py-5" id="products">
|
||||
|
|
|
|||
32
resources/views/fo/partials/hot-news.blade.php
Normal file
32
resources/views/fo/partials/hot-news.blade.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<div class="container-fluid">
|
||||
<div class="row p-4">
|
||||
<div class="col-6">
|
||||
{{-- FIXME: changer l'image pour l'image du model news ainsi que le texte --}}
|
||||
<img class="img-fluid" src="{{ Vite::asset('resources/assets/images/tmp/nuggets.png') }}" alt="">
|
||||
</div>
|
||||
<div class="col-6 text-center">
|
||||
LOREM IPSUM
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row p-4">
|
||||
<div class="col-6">
|
||||
{{-- FIXME: changer l'image pour l'image du model news ainsi que le texte --}}
|
||||
<img class="img-fluid" src="{{ Vite::asset('resources/assets/images/tmp/nuggets.png') }}" alt="">
|
||||
</div>
|
||||
<div class="col-6 text-center">
|
||||
LOREM IPSUM
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-8 rotate-left-5 f-bakerie-rough fs-4 fw-bolder">
|
||||
{{ $hotNewsSettings->value['text'] }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row ps-4 pe-4 pb-4 pt-2">
|
||||
<div class="col-12 text-center">
|
||||
<img class="img-fluid" src="{{ asset($hotNewsSettings->value['picture']) }}" alt="{{ $hotNewsSettings->value['picture_alt'] }}" title="{{ $hotNewsSettings->value['picture_title'] }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
// FIXME: Add missing routes for RangesSliderComponent.vue
|
||||
window.__SYSTEM._routes['fo.home.products'] = '{{ route('fo.home.products', ['range_slug' => 'RANGESLUG']) }}';
|
||||
window.__SYSTEM._routes['fo.contact.show'] = '{{ route('fo.contact.show') }}';
|
||||
window.__SYSTEM._routes['fo.home.hotnews'] = '{{ route('fo.home.hotnews') }}';
|
||||
window.__SYSTEM._routes['fo.add-single-optin'] = '{{ route('fo.add-single-optin') }}';
|
||||
window.__SYSTEM._routes['bo.menu_node_data.index'] = '{{ route('bo.menu_node_data.index') }}';
|
||||
window.__SYSTEM._routes['bo.menu_node_data.update'] = '{{ route('bo.menu_node_data.update', ['menu_node_data' => 'MENU_NODE_DATA']) }}';
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ Route::middleware(['throttle:credentials'])
|
|||
'/accueil/produits-par-gamme/{range_slug}',
|
||||
[ProductController::class, 'jsonGetProductsViewsByRange']
|
||||
)->name('home.products');
|
||||
Route::post('/accueil/actualites_chaudes', [HomeController::class, 'updateHotNewsSatus'])
|
||||
->name('home.hotnews');
|
||||
Route::get('/recrutement', [StaticPageController::class, 'recruitment'])->name('recruitment.show');
|
||||
Route::get('/mentions-legales', [StaticPageController::class, 'legals'])->name('legals.show');
|
||||
Route::get('/charte-de-confidentialite', [StaticPageController::class, 'policies'])->name('policies.show');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue