Compare commits

...
Sign in to create a new pull request.

5 commits

Author SHA1 Message Date
Vincent BRIDIER
b10377bd43 Merge branch 'bugs-fix' into 'main'
fix: multiple bugs #1

See merge request ldc-web/projets/gen-game-web-themes/default-theme!3
2025-08-06 06:38:19 +00:00
Corentin Huet
0d76607889 fix: multiple bugs 2025-08-05 15:58:48 +02:00
Vincent BRIDIER
94049ba518 Merge branch 'newsletters' into 'main'
Added the newsletter field in the footer

See merge request ldc-web/projets/gen-game-web-themes/default-theme!2
2025-06-27 07:35:56 +00:00
Vincent BRIDIER
b42d8f3bd4 Merge branch 'fix-header-count' into 'main'
fix header counter

See merge request ldc-web/projets/gen-game-web-themes/default-theme!1
2025-06-27 07:35:32 +00:00
Noah Lancien
ee86923ac2 Added the newsletter field in the footer 2024-05-06 18:02:23 +02:00
12 changed files with 136 additions and 62 deletions

View file

@ -41,53 +41,4 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
}, 300); }, 300);
} }
const scrollTop = (target: string, offset: number = 0) => {
const targetElement = document.getElementById(target);
if (!targetElement) throw new Error(`scrollTop requires ${target} to exist`);
const top = targetElement.getBoundingClientRect().top,
t = window.scrollY + top - offset;
scrollTo({
top: t,
behavior: "smooth"
});
};
const pageUp = document.getElementById("page-up");
if (pageUp) {
pageUp.addEventListener("click", () => scrollTop("content-container", 250)),
document.addEventListener("scroll", () => {
if (window.scrollY > 250) {
pageUp.classList.add("show");
return;
}
pageUp.classList.remove("show");
});
}
});
// * Input Validation.
document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll("input.is-invalid").forEach((input) => {
let timer: NodeJS.Timeout|null = null;
input.addEventListener("change", () => {
const parent = input.parentElement;
input.classList.remove("is-invalid");
if (parent && parent.classList.contains("is-invalid")) {
parent.classList.remove("is-invalid");
}
});
input.addEventListener("input", () => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
const parent = input.parentElement;
input.classList.remove("is-invalid");
if (parent && parent.classList.contains("is-invalid")) {
parent.classList.remove("is-invalid");
}
}, 250);
});
});
}); });

View file

@ -10,6 +10,11 @@ import "./utilities/vue-fo";
// CUSTOM // CUSTOM
import "./base/common"; import "./base/common";
// PARTIALS
import "./partials/input-errors-removal";
import "./partials/newsletter";
import "./partials/scroll-to-top";
// PAGES // PAGES
import "./pages/home"; import "./pages/home";
import "./pages/products"; import "./pages/products";

View file

@ -0,0 +1,25 @@
// * Input Validation.
document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll("input.is-invalid").forEach((input) => {
let timer: NodeJS.Timeout|null = null;
input.addEventListener("change", () => {
const parent = input.parentElement;
input.classList.remove("is-invalid");
if (parent && parent.classList.contains("is-invalid")) {
parent.classList.remove("is-invalid");
}
});
input.addEventListener("input", () => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
const parent = input.parentElement;
input.classList.remove("is-invalid");
if (parent && parent.classList.contains("is-invalid")) {
parent.classList.remove("is-invalid");
}
}, 250);
});
});
});

49
ts/partials/newsletter.ts Normal file
View file

@ -0,0 +1,49 @@
import route from "../../../../ts/modules/route";
const laravelRoute = route.methods.route;
document.addEventListener("DOMContentLoaded", function () {
// * NEWSLETTERS
// Subscribe to newsletter
const newsletterSubmitBtn = document.getElementById("newsletter-submit");
const newsletterEmailInput = document.getElementById("newsletter-email") as HTMLInputElement;
const newsletterMessageDiv = document.getElementById("newsletter-message");
if (newsletterSubmitBtn && newsletterEmailInput && newsletterMessageDiv) {
// Submit the request
newsletterSubmitBtn.addEventListener("click", function () {
// Reset error field
newsletterMessageDiv.classList.remove("bg-success-subtle", "border-success", "text-success");
newsletterMessageDiv.classList.remove("bg-danger-subtle", "border-danger", "text-danger");
newsletterMessageDiv.textContent = "";
const addSingleOptinRoute = laravelRoute("fo.add-single-optin");
if (addSingleOptinRoute === null) {
return;
}
window.axios.post(addSingleOptinRoute, {
email: newsletterEmailInput.value,
})
.then(function (response) {
newsletterMessageDiv.classList.remove("d-none");
newsletterMessageDiv.classList.add("bg-success-subtle", "border-success", "text-success");
newsletterMessageDiv.textContent = String(response.data);
newsletterEmailInput.value = "";
})
.catch(function (error) {
newsletterMessageDiv.classList.remove("d-none");
newsletterMessageDiv.classList.add("bg-danger-subtle", "border-danger", "text-danger");
if (error.response.status == 422) {
const errors = error.response.data.errors;
for (const errorKey in errors) {
const errorP = document.createElement("p");
errorP.classList.add("m-0");
errorP.textContent = errors[errorKey];
newsletterMessageDiv.appendChild(errorP);
}
} else {
newsletterMessageDiv.textContent = error.response.data;
}
});
});
}
});

View file

@ -0,0 +1,25 @@
// * Scroll to top button.
document.addEventListener("DOMContentLoaded", function () {
const scrollTop = (target: string, offset: number = 0) => {
const targetElement = document.getElementById(target);
if (!targetElement) throw new Error(`scrollTop requires ${target} to exist`);
const top = targetElement.getBoundingClientRect().top,
t = window.scrollY + top - offset;
scrollTo({
top: t,
behavior: "smooth"
});
};
const pageUp = document.getElementById("page-up");
if (pageUp) {
pageUp.addEventListener("click", () => scrollTop("content-container", 250)),
document.addEventListener("scroll", () => {
if (window.scrollY > 250) {
pageUp.classList.add("show");
return;
}
pageUp.classList.remove("show");
});
}
});

View file

@ -4,7 +4,7 @@
{!! nl2br( {!! nl2br(
clean( clean(
__( __(
"Le mot de passe doit avoir une longueur de 8 caractères minimum,\n doit contenir une lettre majuscule et une lettre minucule,\n doit contenir un caractère spécial comme une virgule par exemple,\n doit contenir un chiffre.", "Le mot de passe doit avoir une longueur de 8 caractères minimum,\n doit contenir une lettre majuscule et une lettre minuscule,\n doit contenir un caractère spécial comme une virgule par exemple,\n doit contenir un chiffre.",
), ),
), ),
) !!} ) !!}

View file

@ -0,0 +1,12 @@
{{-- Newsletter form --}}
<div class="d-inline-block fs-3 p-3">
<span>{{ __('Inscrivez-vous à notre newsletter') }}</span>
<div class="d-inline-block">
<div class="d-flex">
<input class="form-control mx-2" id="newsletter-email" type="email" placeholder="mon@email.com">
<button class="btn btn-primary text-uppercase fs-4" id="newsletter-submit" type="submit">{{ __('Valider') }}</button>
{{-- Error/Success message container --}}
</div>
</div>
<div class="d-none fs-6 rounded-2 my-3 border p-3" id="newsletter-message"></div>
</div>

View file

@ -1,6 +1,7 @@
<div class="row text-bg-quad"> <div class="row text-bg-quad">
<div class="col-12 col-md-9 col-xl-10"> <div class="col-12 col-md-9 col-xl-10">
@include('theme::layouts.footer-links') @include('theme::layouts.footer-links')
@include('theme::layouts.footer-newsletter')
{{-- LINKS --}} {{-- LINKS --}}
<nav class="ms-md-5 footer-nav p-3"> <nav class="ms-md-5 footer-nav p-3">

View file

@ -58,7 +58,7 @@
<span class="d-flex justify-content-center"> <span class="d-flex justify-content-center">
<span <span
class="rounded-pill text-tertiary fw-bold fs-4 d-flex align-items-center my-1 bg-white px-3 py-1"> class="rounded-pill text-tertiary fw-bold fs-4 d-flex align-items-center my-1 bg-white px-3 py-1">
{{ $prizeModel->quantity -\App\Models\InstantWin::query()->whereHas('prize', fn($q) => $q->where('id', $prizeModel->id))->whereHas('participation')->count() }} {{ $prizeModel->quantity - \App\Models\InstantWin::query()->whereHas('prize', fn($q) => $q->where('id', $prizeModel->id))->whereHas('participation')->count() }}
</span> </span>
<span <span
class="fw-bold text-uppercase fs-5 lh-sm d-flex align-items-center mx-2">{{ $prizeModel->label }}</span> class="fw-bold text-uppercase fs-5 lh-sm d-flex align-items-center mx-2">{{ $prizeModel->label }}</span>

View file

@ -1,6 +1,7 @@
<div class="row text-bg-quad"> <div class="row text-bg-quad">
<div class="col-12 col-md-9 col-xl-10"> <div class="col-12 col-md-9 col-xl-10">
@include('theme::layouts.footer-links') @include('theme::layouts.footer-links')
@include('theme::layouts.footer-newsletter')
{{-- LINKS --}} {{-- LINKS --}}
<ul class="list-inline ms-md-5 p-3"> <ul class="list-inline ms-md-5 p-3">

View file

@ -14,7 +14,7 @@
<div class="row mb-5"> <div class="row mb-5">
<div class="col"> <div class="col">
<a class="btn btn-lg btn-success" data-bs-toggle="tooltip" href="{{ route('fo.participate') }}" <a class="btn btn-lg btn-success" data-bs-toggle="tooltip" href="{{ route('fo.participate') }}"
title="{{ __('Retenter votre change avec un nouveau code unique') }}">{{ __('Rejouer !') }}</a> title="{{ __('Retenter votre chance avec un nouveau code unique') }}">{{ __('Rejouer !') }}</a>
</div> </div>
</div> </div>
</div> </div>

View file

@ -14,20 +14,25 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<div class="d-flex product-list justify-content-center flex-wrap"> @foreach ($rangeModelList as $rangeModel)
@foreach ($rangeModelList as $rangeModel) <h2 class="text-secondary">{{ $rangeModel->name }}</h2>
<div class="d-flex product-list justify-content-center flex-wrap">
@foreach ($rangeModel->products as $productModel) @foreach ($rangeModel->products as $productModel)
<div class="card product m-2"> <div class="card product m-2">
<a class="card-body glightbox" href="{{ asset($productModel->picture) }}" role="button" @if (!empty($productModel->picture))
aria-label="{{ __('Afficher l\'image en plein écran') }}" tabindex="0"> <a class="card-body glightbox" href="{{ asset($productModel->picture) }}" role="button"
<img class="card-img-top" src="{{ asset($productModel->picture) }}" aria-label="{{ __('Afficher l\'image en plein écran') }}" tabindex="0">
title="{{ $productModel->picture_title }}" alt="{{ $productModel->picture_alt }}"> <img class="card-img-top" src="{{ asset($productModel->picture) }}"
<span class="h4 card-title">{{ Str::title($productModel->name) }}</span> title="{{ $productModel->picture_title }}" alt="{{ $productModel->picture_alt }}">
</a> <span class="h4 card-title">{{ Str::title($productModel->name) }}</span>
</a>
@else
<span class="h4 card-title p-2">{{ Str::title($productModel->name) }}</span>
@endif
</div> </div>
@endforeach @endforeach
@endforeach </div>
</div> @endforeach
</div> </div>
</div> </div>
</div> </div>