FEATURE Big toolbar refactor to handle share like and cita buttons directly from carhop theme
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Antoine M 2026-05-28 17:50:27 +02:00
parent 192d79b1d0
commit 67a20df2cc
8 changed files with 342 additions and 5 deletions

View File

@ -19,6 +19,18 @@ add_action('rest_api_init', function () {
'callback' => 'build_fonds_archives_posts_by_letter',
'permission_callback' => '__return_true',
));
/* ----------------
INTERACTIONS ROUTES
-----------------*/
// ################ LIKE POST ################
register_rest_route('carhop-datas/v1/interactions', '/posts/like', array(
'methods' => 'POST',
'callback' => 'carhop_like_post',
'permission_callback' => '__return_true',
));
});
function carhop_posts_where_starts_with_letter($where, $query)
@ -217,3 +229,45 @@ function build_fonds_archives_posts_by_letter($request)
return $response;
}
function carhop_like_post($request)
{
$post_id = $request->get_param('post_id');
if (!$post_id) {
return new WP_Error('post_id_required', 'Post ID is required', array('status' => 400));
}
$post_id = intval($post_id);
// Vérifier que le post existe
if (!get_post($post_id)) {
return new WP_Error('post_not_found', 'Post non trouvé', array('status' => 404));
}
$likes_count = get_post_likes_count($post_id);
// Incrémenter le compteur
$new_likes = $likes_count + 1;
// Mettre à jour la meta
update_post_meta($post_id, 'likes_count', $new_likes);
$response_data = array(
'success' => true,
'post_id' => $post_id,
'likes_count' => $new_likes,
'message' => 'Like ajouté avec succès'
);
$response = new WP_REST_Response($response_data);
$response->set_status(200);
return $response;
}

View File

@ -1,6 +1,6 @@
.entry-content,
.site-content {
a[target='_blank']:not(.page-header__cta) {
a[target='_blank']:not(.page-header__cta, .share-link) {
@apply external-link;
}
}

View File

@ -7,7 +7,6 @@ import { searchBarInit } from './search-bar';
import singlesInit from './singles/singles';
import archivesInit from './archives/archives';
import archivesFondsArchivesInit from './archives/archives-fonds-archives';
import handleCiteButton from './singles/cite-button';
import titlesInit from './titles';
import {
pageHeaderAnimationInit,
@ -24,7 +23,6 @@ window.addEventListener('load', function () {
singlesInit();
archivesInit();
archivesFondsArchivesInit();
handleCiteButton();
titlesInit();
pageHeaderAnimationInit();
chapterSectionAnimationInit();

View File

@ -0,0 +1,243 @@
// =============================================================================
// TYPE DECLARATIONS
// =============================================================================
declare var Notyf: any;
// =============================================================================
// UTILITY FUNCTIONS
// =============================================================================
function getPostId() {
const postId = document.querySelector('.page-single')?.getAttribute('data-post-id');
if (!postId) return;
return postId;
}
function getPostType() {
const postType = document.querySelector('.page-single')?.getAttribute('data-post-type');
if (!postType) return;
return postType;
}
// =============================================================================
// LIKE TRACKING FUNCTIONS
// =============================================================================
/**
* Clé localStorage pour stocker les posts likés
*/
const LIKED_POSTS_KEY = 'dynamiques_liked_posts';
/**
* Récupère la liste des posts likés depuis localStorage
*/
function getLikedPosts(): string[] {
try {
const likedPosts = localStorage.getItem(LIKED_POSTS_KEY);
return likedPosts ? JSON.parse(likedPosts) : [];
} catch (error) {
console.error('Erreur lecture localStorage:', error);
return [];
}
}
/**
* Ajoute un post à la liste des posts likés
*/
function addLikedPost(postId: string): void {
try {
const likedPosts = getLikedPosts();
if (!likedPosts.includes(postId)) {
likedPosts.push(postId);
localStorage.setItem(LIKED_POSTS_KEY, JSON.stringify(likedPosts));
}
} catch (error) {
console.error('Erreur sauvegarde localStorage:', error);
}
}
/**
* Vérifie si un post a déjà é liké
*/
function isPostLiked(postId: string): boolean {
const likedPosts = getLikedPosts();
return likedPosts.includes(postId);
}
// =============================================================================
// LIKE API FUNCTIONS
// =============================================================================
async function likePost(postId: string): Promise<boolean> {
// Vérifier si le post a déjà été liké
if (isPostLiked(postId)) {
console.log(`Post ${postId} déjà liké !`);
showAlreadyLikedMessage();
return false;
}
try {
const response = await fetch(`/wp-json/carhop-datas/v1/interactions/posts/like`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
post_id: postId,
}),
});
const data = await response.json();
if (data.success) {
console.log(`Post ${postId} liké ! Nouveau total: ${data.likes_count} likes`);
// Sauvegarder le like dans localStorage
addLikedPost(postId);
// Mettre à jour l'interface utilisateur
updateLikeDisplay(data.likes_count);
updateLikeButtonState();
// Afficher message de succès
showLikeSuccessMessage(data.likes_count);
return true;
} else {
console.error('Erreur API:', data);
return false;
}
} catch (error) {
console.error('Erreur lors du like:', error);
return false;
}
}
// =============================================================================
// UI UPDATE FUNCTIONS
// =============================================================================
function updateLikeDisplay(likesCount: number) {
// Mettre à jour l'affichage du compteur de likes dans l'interface
const likeCountElement = document.querySelector('.socials-buttons .likes-count');
const likeButton = document.querySelector('.socials-buttons__button--like');
if (likeCountElement && likeButton) {
likeButton.setAttribute('data-likes-count', `${likesCount}`);
likeButton.classList.add('is-disabled');
likeCountElement.textContent = `${likesCount}`;
}
}
function updateLikeButtonState() {
const postId = getPostId();
const likeButton = document.querySelector('.socials-buttons__button--like');
if (!postId || !likeButton) return;
const hasAlreadyLiked = isPostLiked(postId);
if (hasAlreadyLiked) {
const actionText = likeButton.querySelector('.button-action-text');
if (actionText) {
actionText.textContent = 'Déjà liké';
}
likeButton.setAttribute('title', 'Déjà liké !');
return;
}
if (!hasAlreadyLiked) {
likeButton.classList.remove('is-disabled');
}
}
function updateLikesCountIndicator() {
const likesCountIndicator = likeButton.querySelector('.likes-count');
const likesCount = likeButton.getAttribute('data-likes-count');
if (likesCount && likesCountIndicator) {
likesCountIndicator.textContent = `${parseInt(likesCount) + 1}`;
}
}
function showAlreadyLikedMessage() {
const notyf = new Notyf({
duration: 3000,
ripple: false,
dismissible: true,
types: [
{
type: 'error',
background: '#ff6b6b',
icon: {
className: 'notyf__icon--error',
tagName: 'i',
// Pas de text personnalisé pour garder l'icône d'erreur par défaut
},
},
],
position: {
x: 'right',
y: 'top',
},
});
notyf.error(' Vous avez déjà liké ce post ! ❤️');
}
function showLikeSuccessMessage(likesCount: number) {
const notyf = new Notyf({
duration: 2000,
ripple: false,
dismissible: true,
types: [
{
type: 'success',
background: '#10B981',
icon: {
className: 'notyf__icon--success',
tagName: 'i',
text: '❤️',
},
},
],
position: {
x: 'right',
y: 'top',
},
});
notyf.success(
`Merci pour votre like ! <br>Total: ${likesCount} like${likesCount > 1 ? 's' : ''}`,
);
}
// =============================================================================
// MAIN INITIALIZATION FUNCTION
// =============================================================================
export default function handleLikeButton(): void {
const likeButton: HTMLElement | null = document.querySelector(
'.socials-buttons .socials-buttons__button--like',
);
const postType = getPostType();
const postId = getPostId();
if (!postType || !postId || !likeButton) return;
updateLikeButtonState();
// Ajouter l'événement click
likeButton.addEventListener('click', async (e) => {
e.preventDefault(); // Empêcher comportement par défaut
const hasAlreadyLiked = isPostLiked(postId);
if (hasAlreadyLiked) return showAlreadyLikedMessage();
// Désactiver temporairement le bouton pour éviter les clics multiples
likeButton.style.pointerEvents = 'none';
const success = await likePost(postId);
// Réactiver le bouton
setTimeout(() => {
likeButton.style.pointerEvents = 'auto';
}, 1000);
});
}

View File

@ -0,0 +1,36 @@
export default function handleShareButton() {
const shareButton = document.querySelector('.socials-buttons__button--share');
if (!shareButton) return;
shareButton.addEventListener('click', () => {
const isOpen = shareButton.classList.contains('is-open');
if (!isOpen) {
shareButton.classList.add('is-open');
} else {
shareButton.classList.remove('is-open');
}
});
handleCopyLinkButton();
}
function handleCopyLinkButton() {
const copyLinkButton = document.querySelector('.share-button--copy-link a');
if (!copyLinkButton) return;
copyLinkButton.addEventListener('click', (e) => {
e.preventDefault();
const url = copyLinkButton.getAttribute('data-url');
if (!url) return;
navigator.clipboard.writeText(url);
const notyf = new Notyf({
duration: 4000,
ripple: false,
dismissible: true,
position: {
x: 'right',
y: 'top',
},
});
notyf.success('Lien copié !');
});
}

View File

@ -1,5 +1,11 @@
import { handlePostToolbar } from './post-toolbar.ts';
import handleCiteButton from './cite-button.ts';
import handleLikeButton from './like-button.ts';
import handleShareButton from './share-button.ts';
export default function singles(): void {
handlePostToolbar();
handleCiteButton();
handleLikeButton();
handleShareButton();
}

View File

@ -5,7 +5,7 @@
$postType = get_post_type();
?>
<div class="page-single page-single--<?php echo $postType; ?>" data-article-id="<?php echo get_the_ID(); ?>">
<div class="page-single page-single--<?php echo $postType; ?>" data-post-id="<?php echo get_the_ID(); ?>" data-post-type="<?php echo $postType; ?>">
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('template-parts/components/posts/post-header', null, array(

View File

@ -7,7 +7,7 @@ $postType = get_post_type();
<div class="page-single page--single-<?php echo $postType; ?>" data-article-id="<?php echo get_the_ID(); ?>">
<div class="page-single page--single-<?php echo $postType; ?>" data-post-id="<?php echo get_the_ID(); ?>" data-post-type="<?php echo $postType; ?>">
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('template-parts/components/posts/post-header'); ?>