140 lines
4.4 KiB
JavaScript
140 lines
4.4 KiB
JavaScript
import { useState, useEffect } from '@wordpress/element';
|
|
|
|
function isOpenNow(operatingHours = []) {
|
|
if (!operatingHours.length) return null;
|
|
|
|
const now = new Date();
|
|
const dayNames = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
|
|
const today = dayNames[now.getDay()];
|
|
const todaysHours = operatingHours.filter(h => h.day === today);
|
|
if (!todaysHours.length) return null;
|
|
|
|
for (let h of todaysHours) {
|
|
if (h.closed) continue;
|
|
if (h.open_24_hours) return true;
|
|
if (!h.opening_time || !h.closing_time) continue;
|
|
|
|
const [openH, openM] = h.opening_time.split(':').map(Number);
|
|
const [closeH, closeM] = h.closing_time.split(':').map(Number);
|
|
|
|
const openDate = new Date(now);
|
|
openDate.setHours(openH, openM, 0, 0);
|
|
const closeDate = new Date(now);
|
|
closeDate.setHours(closeH, closeM, 0, 0);
|
|
|
|
if (now >= openDate && now <= closeDate) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
export default function DirectoryListingItem({
|
|
post,
|
|
imageSrc = '',
|
|
imageMediaID = null,
|
|
restRoot = '', // must pass multisite REST root from View.js
|
|
onQuickView,
|
|
style = 'hero',
|
|
displayCategoryTitle = '',
|
|
displayCategoryURL = '#',
|
|
operatingHours = [],
|
|
titleTag,
|
|
postDescription,
|
|
}) {
|
|
const [finalImageSrc, setFinalImageSrc] = useState(imageSrc);
|
|
const [isOpen, setIsOpen] = useState(null);
|
|
const TitleTag = titleTag || 'h3';
|
|
|
|
useEffect(() => {
|
|
setIsOpen(isOpenNow(operatingHours));
|
|
}, [operatingHours]);
|
|
|
|
// Fetch image URL if imageMediaID is provided
|
|
useEffect(() => {
|
|
if (!imageMediaID) return;
|
|
if (!restRoot) {
|
|
console.error('DirectoryListingItem: restRoot is required for multisite media fetch.');
|
|
return;
|
|
}
|
|
|
|
let isMounted = true;
|
|
const url = `${restRoot}wp/v2/media/${imageMediaID}`;
|
|
console.log('Fetching media URL:', url);
|
|
|
|
fetch(url)
|
|
.then(res => {
|
|
if (!res.ok) throw new Error(`Media fetch failed: ${res.status}`);
|
|
return res.json();
|
|
})
|
|
.then(data => {
|
|
if (isMounted && data?.source_url) {
|
|
setFinalImageSrc(data.source_url);
|
|
}
|
|
})
|
|
.catch(err => console.error('Failed to fetch media:', err));
|
|
|
|
return () => { isMounted = false; };
|
|
}, [imageMediaID, restRoot]);
|
|
|
|
const heroStyle = style === 'hero' && finalImageSrc ? { backgroundImage: `url(${finalImageSrc})` } : {};
|
|
|
|
const content = (
|
|
<>
|
|
{style !== 'hero' && (
|
|
<div className="listing-left">
|
|
{finalImageSrc ? (
|
|
<img src={finalImageSrc} alt={post.title?.rendered || 'Post image'} />
|
|
) : (
|
|
<div className="placeholder-image">No Image</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
<div className="listing-right">
|
|
{displayCategoryTitle && (
|
|
<a
|
|
className="listing-category-button"
|
|
href={displayCategoryURL}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
{displayCategoryTitle}
|
|
</a>
|
|
)}
|
|
|
|
<TitleTag>
|
|
{post.title?.rendered ? (
|
|
<a href={post.link} dangerouslySetInnerHTML={{ __html: post.title.rendered }} />
|
|
) : (
|
|
<span>No title</span>
|
|
)}
|
|
</TitleTag>
|
|
|
|
{postDescription ? (
|
|
<p dangerouslySetInnerHTML={{ __html: postDescription }} />
|
|
) : null}
|
|
|
|
{isOpen !== null && (
|
|
<span className={`open-status ${isOpen ? 'open' : 'closed'}`}>
|
|
{isOpen ? 'Open' : 'Closed'}
|
|
</span>
|
|
)}
|
|
|
|
<button className="quickview-button" onClick={() => onQuickView(post)}>
|
|
QuickView
|
|
</button>
|
|
</div>
|
|
</>
|
|
);
|
|
|
|
return style === 'hero' ? (
|
|
<a href={post.link} className={`directory-listing ${style}`} style={heroStyle}>
|
|
{content}
|
|
</a>
|
|
) : (
|
|
<article className={`directory-listing ${style}`} style={heroStyle}>
|
|
{content}
|
|
</article>
|
|
);
|
|
}
|