Files
GNX-WEB/frontEnd/components/pages/case-study/CaseSingle.tsx
Iliyan Angelov 6a9e823402 updates
2025-12-10 01:36:00 +02:00

403 lines
15 KiB
TypeScript

"use client";
import { useEffect } from "react";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useCaseStudy } from "@/lib/hooks/useCaseStudy";
import { getImageUrl } from "@/lib/imageUtils";
import { sanitizeHTML } from "@/lib/security/sanitize";
interface CaseSingleProps {
slug: string;
}
const CaseSingle = ({ slug }: CaseSingleProps) => {
const router = useRouter();
const { caseStudy, loading, error } = useCaseStudy(slug);
const handleGoBack = () => {
router.back();
};
// Debug logging
useEffect(() => {
if (error) {
console.error('Error loading case study:', error);
}
if (caseStudy) {
console.log('Case Study Data:', {
title: caseStudy.title,
hasCategory: !!caseStudy.category,
hasClient: !!caseStudy.client,
processStepsCount: caseStudy.process_steps?.length || 0,
relatedCaseStudiesCount: caseStudy.related_case_studies?.length || 0,
hasPosterImage: !!caseStudy.poster_image,
hasProjectImage: !!caseStudy.project_image,
hasFeaturedImage: !!caseStudy.featured_image,
hasProjectOverview: !!caseStudy.project_overview,
hasSiteMapContent: !!caseStudy.site_map_content,
fullData: caseStudy
});
}
}, [caseStudy, error]);
if (loading) {
return (
<section className="case-study-details luxury-case-study fix-top">
<div className="container">
<div className="row">
<div className="col-12">
<div className="loading-state">
<div className="loading-spinner"></div>
<p className="text-center">Loading case study...</p>
</div>
</div>
</div>
</div>
</section>
);
}
if (error || !caseStudy) {
return (
<section className="case-study-details luxury-case-study fix-top">
<div className="container">
<div className="row">
<div className="col-12">
<div className="error-state">
<h2>Case Study Not Found</h2>
<p>The case study you&apos;re looking for doesn&apos;t exist or has been removed.</p>
<Link href="/case-study" className="btn btn-primary">
View All Case Studies
</Link>
</div>
</div>
</div>
</div>
</section>
);
}
return (
<>
{/* Hero Banner Section */}
<section className="case-study-hero luxury-case-hero fix-top">
<div className="hero-background-overlay"></div>
<div className="container">
<div className="row">
<div className="col-12">
<div className="case-study-hero-content">
{/* Category Badge */}
{caseStudy.category && (
<div className="hero-badge">
<i className="fa-solid fa-folder-open"></i>
<span>{caseStudy.category.name}</span>
</div>
)}
{/* Title */}
<h1 className="hero-title">
{caseStudy.title}
</h1>
{/* Subtitle */}
{caseStudy.subtitle && (
<h2 className="hero-subtitle">
{caseStudy.subtitle}
</h2>
)}
{/* Meta Information */}
<div className="hero-meta">
{caseStudy.client && (
<div className="meta-item">
<i className="fa-solid fa-building"></i>
<span>{caseStudy.client.name}</span>
</div>
)}
{caseStudy.published_at && (
<div className="meta-item">
<i className="fa-solid fa-calendar"></i>
<span>{new Date(caseStudy.published_at).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}</span>
</div>
)}
{caseStudy.views_count !== undefined && (
<div className="meta-item">
<i className="fa-solid fa-eye"></i>
<span>{caseStudy.views_count} views</span>
</div>
)}
</div>
</div>
</div>
</div>
</div>
{/* Hero Image */}
{caseStudy.featured_image && (
<div className="hero-image-container">
<div className="hero-image-wrapper">
<Image
src={getImageUrl(caseStudy.featured_image)}
alt={caseStudy.title}
fill
className="hero-image"
priority
sizes="100vw"
style={{ objectFit: 'cover' }}
/>
</div>
<div className="hero-image-overlay"></div>
</div>
)}
</section>
{/* Main Content Section */}
<section className="case-study-details luxury-case-study">
<div className="container">
{/* Back Button - Top */}
<div className="row pt-60">
<div className="col-12">
<button
onClick={handleGoBack}
className="btn btn-outline mb-40"
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '10px',
padding: '14px 28px',
fontSize: '16px',
fontWeight: 600,
cursor: 'pointer',
border: '2px solid #007bff',
backgroundColor: '#007bff',
color: '#ffffff',
borderRadius: '6px',
transition: 'all 0.3s ease',
boxShadow: '0 2px 8px rgba(0, 123, 255, 0.3)'
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = '#0056b3';
e.currentTarget.style.borderColor = '#0056b3';
e.currentTarget.style.boxShadow = '0 4px 12px rgba(0, 123, 255, 0.4)';
e.currentTarget.style.transform = 'translateY(-2px)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = '#007bff';
e.currentTarget.style.borderColor = '#007bff';
e.currentTarget.style.boxShadow = '0 2px 8px rgba(0, 123, 255, 0.3)';
e.currentTarget.style.transform = 'translateY(0)';
}}
>
<i className="fa-solid fa-arrow-left"></i>
<span>Back to Case Studies</span>
</button>
</div>
</div>
{/* Project Overview Section */}
<div className="row vertical-column-gap-lg align-items-start">
<div className="col-12 col-lg-7">
<div className="case-study-content">
<h2 className="section-title">Project Overview</h2>
{caseStudy.project_overview ? (
<div
className="content-html"
dangerouslySetInnerHTML={{ __html: sanitizeHTML(caseStudy.project_overview) }}
/>
) : (
<div
className="content-html"
dangerouslySetInnerHTML={{ __html: sanitizeHTML(caseStudy.description || '') }}
/>
)}
{/* Full Description Content */}
{caseStudy.description && (
<div
className="content-html full-description mt-40"
dangerouslySetInnerHTML={{ __html: sanitizeHTML(caseStudy.description) }}
/>
)}
</div>
</div>
<div className="col-12 col-lg-5">
<div className="case-study-sidebar">
{/* Project Image */}
{caseStudy.project_image && (
<div className="sidebar-image mb-40">
<div className="image-wrapper">
<Image
src={getImageUrl(caseStudy.project_image)}
alt={`${caseStudy.title} - Project`}
width={600}
height={500}
className="project-image"
/>
</div>
</div>
)}
{/* Project Info Card */}
<div className="info-card">
<h3 className="info-card-title">Project Details</h3>
<div className="info-list">
{caseStudy.category && (
<div className="info-item">
<span className="info-label">
<i className="fa-solid fa-tag"></i>
Category
</span>
<span className="info-value">{caseStudy.category.name}</span>
</div>
)}
{caseStudy.client && (
<div className="info-item">
<span className="info-label">
<i className="fa-solid fa-building"></i>
Client
</span>
<span className="info-value">{caseStudy.client.name}</span>
</div>
)}
{caseStudy.published_at && (
<div className="info-item">
<span className="info-label">
<i className="fa-solid fa-calendar"></i>
Published
</span>
<span className="info-value">
{new Date(caseStudy.published_at).toLocaleDateString('en-US', { year: 'numeric', month: 'short' })}
</span>
</div>
)}
{caseStudy.featured && (
<div className="info-item">
<span className="info-label">
<i className="fa-solid fa-star"></i>
Status
</span>
<span className="info-value featured-badge">Featured</span>
</div>
)}
</div>
{caseStudy.client?.website && (
<div className="info-card-footer">
<a
href={caseStudy.client.website}
target="_blank"
rel="noopener noreferrer"
className="btn btn-outline"
>
<i className="fa-solid fa-external-link"></i>
Visit Client Website
</a>
</div>
)}
</div>
</div>
</div>
</div>
{/* Statistics/Metrics Section */}
{caseStudy.description && caseStudy.description.includes('Key Results') && (
<div className="row pt-60">
<div className="col-12">
<div className="case-study-stats">
<h2 className="section-title text-center mb-50">Key Achievements</h2>
<div className="stats-grid">
{(() => {
// Extract metrics from description
const resultsMatch = caseStudy.description.match(/<h3>Key Results<\/h3>[\s\S]*?<ul>([\s\S]*?)<\/ul>/i);
if (resultsMatch) {
const items = resultsMatch[1].match(/<li>([^<]+)<\/li>/g);
if (items && items.length > 0) {
return items.slice(0, 4).map((item, index) => {
const text = item.replace(/<[^>]+>/g, '');
const numberMatch = text.match(/(\d+[%$]?)/);
const number = numberMatch ? numberMatch[1] : '';
const description = text.replace(/\d+[%$]?\s*/, '').trim();
return (
<div key={index} className="stat-card">
<div className="stat-number">{number}</div>
<div className="stat-label">{description}</div>
</div>
);
});
}
}
return null;
})()}
</div>
</div>
</div>
</div>
)}
{/* Site Map / Process Section */}
{caseStudy.site_map_content && (
<div className="row pt-60">
<div className="col-12">
<div className="case-study-section">
<h2 className="section-title">Site Map & Process</h2>
<div
className="content-html"
dangerouslySetInnerHTML={{ __html: sanitizeHTML(caseStudy.site_map_content) }}
/>
</div>
</div>
</div>
)}
{/* Back Button - Bottom */}
<div className="row pt-60 pb-60">
<div className="col-12">
<div style={{ textAlign: 'center' }}>
<button
onClick={handleGoBack}
className="btn btn-outline"
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '10px',
padding: '14px 28px',
fontSize: '16px',
fontWeight: 600,
cursor: 'pointer',
border: '2px solid #007bff',
backgroundColor: '#007bff',
color: '#ffffff',
borderRadius: '6px',
transition: 'all 0.3s ease',
boxShadow: '0 2px 8px rgba(0, 123, 255, 0.3)'
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = '#0056b3';
e.currentTarget.style.borderColor = '#0056b3';
e.currentTarget.style.boxShadow = '0 4px 12px rgba(0, 123, 255, 0.4)';
e.currentTarget.style.transform = 'translateY(-2px)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = '#007bff';
e.currentTarget.style.borderColor = '#007bff';
e.currentTarget.style.boxShadow = '0 2px 8px rgba(0, 123, 255, 0.3)';
e.currentTarget.style.transform = 'translateY(0)';
}}
>
<i className="fa-solid fa-arrow-left"></i>
<span>Back to Case Studies</span>
</button>
</div>
</div>
</div>
</div>
</section>
</>
);
};
export default CaseSingle;