This commit is contained in:
Iliyan Angelov
2025-10-13 01:49:06 +03:00
parent 76c857b4f5
commit 5ad9cbe3a6
97 changed files with 5752 additions and 2376 deletions

View File

@@ -1,183 +0,0 @@
"use client";
import { useState, useRef } from "react";
import Image from "next/image";
import { useServiceManagement } from "@/lib/hooks/useServices";
interface ServiceImageUploadProps {
serviceSlug: string;
currentImageUrl?: string;
onImageUploaded?: (service: any) => void;
}
const ServiceImageUpload: React.FC<ServiceImageUploadProps> = ({
serviceSlug,
currentImageUrl,
onImageUploaded,
}) => {
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const [uploading, setUploading] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const { uploadServiceImage, loading, error } = useServiceManagement();
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
// Validate file type
if (!file.type.startsWith('image/')) {
alert('Please select an image file');
return;
}
// Validate file size (5MB limit)
if (file.size > 5 * 1024 * 1024) {
alert('File size must be less than 5MB');
return;
}
setSelectedFile(file);
// Create preview URL
const url = URL.createObjectURL(file);
setPreviewUrl(url);
}
};
const handleUpload = async () => {
if (!selectedFile) return;
try {
setUploading(true);
const updatedService = await uploadServiceImage(serviceSlug, selectedFile);
// Clean up preview URL
if (previewUrl) {
URL.revokeObjectURL(previewUrl);
}
setSelectedFile(null);
setPreviewUrl(null);
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
if (onImageUploaded) {
onImageUploaded(updatedService);
}
alert('Image uploaded successfully!');
} catch (err) {
console.error('Upload failed:', err);
alert('Failed to upload image. Please try again.');
} finally {
setUploading(false);
}
};
const handleCancel = () => {
setSelectedFile(null);
if (previewUrl) {
URL.revokeObjectURL(previewUrl);
setPreviewUrl(null);
}
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
};
return (
<div className="service-image-upload">
<div className="mb-3">
<label htmlFor="image-upload" className="form-label">
Service Image
</label>
<input
ref={fileInputRef}
type="file"
id="image-upload"
className="form-control"
accept="image/*"
onChange={handleFileSelect}
disabled={uploading || loading}
/>
<div className="form-text">
Select an image file (JPG, PNG, GIF). Maximum size: 5MB.
</div>
</div>
{/* Current Image */}
{currentImageUrl && !previewUrl && (
<div className="mb-3">
<label className="form-label">Current Image:</label>
<div className="current-image">
<Image
src={currentImageUrl}
alt="Current service image"
className="img-thumbnail"
width={200}
height={200}
style={{ maxWidth: '200px', maxHeight: '200px', objectFit: 'cover' }}
/>
</div>
</div>
)}
{/* Preview */}
{previewUrl && (
<div className="mb-3">
<label className="form-label">Preview:</label>
<div className="image-preview">
<Image
src={previewUrl}
alt="Preview"
className="img-thumbnail"
width={200}
height={200}
style={{ maxWidth: '200px', maxHeight: '200px', objectFit: 'cover' }}
/>
</div>
</div>
)}
{/* Error Display */}
{error && (
<div className="alert alert-danger" role="alert">
{error}
</div>
)}
{/* Action Buttons */}
{selectedFile && (
<div className="d-flex gap-2">
<button
type="button"
className="btn btn-primary"
onClick={handleUpload}
disabled={uploading || loading}
>
{uploading || loading ? (
<>
<span className="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
Uploading...
</>
) : (
'Upload Image'
)}
</button>
<button
type="button"
className="btn btn-secondary"
onClick={handleCancel}
disabled={uploading || loading}
>
Cancel
</button>
</div>
)}
</div>
);
};
export default ServiceImageUpload;

View File

@@ -1,137 +0,0 @@
'use client';
import { useState } from 'react';
export default function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
subject: '',
message: ''
});
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
setFormData({
...formData,
[e.target.name]: e.target.value
});
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError(null);
// Simulate form submission
setTimeout(() => {
setSuccess(true);
setFormData({ name: '', email: '', subject: '', message: '' });
setLoading(false);
}, 2000);
};
if (success) {
return (
<div className="alert alert-success" role="alert">
<h4 className="alert-heading">Message Sent!</h4>
<p>Thank you for your message. We&apos;ll get back to you soon.</p>
<button
className="btn btn-outline-success"
onClick={() => setSuccess(false)}
>
Send Another Message
</button>
</div>
);
}
return (
<div className="container py-5">
<div className="row justify-content-center">
<div className="col-md-8">
<h2 className="text-center mb-4">Contact Us</h2>
{error && (
<div className="alert alert-danger" role="alert">
{error}
</div>
)}
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col-md-6 mb-3">
<label htmlFor="name" className="form-label">Name *</label>
<input
type="text"
className="form-control"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
required
/>
</div>
<div className="col-md-6 mb-3">
<label htmlFor="email" className="form-label">Email *</label>
<input
type="email"
className="form-control"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
required
/>
</div>
</div>
<div className="mb-3">
<label htmlFor="subject" className="form-label">Subject</label>
<input
type="text"
className="form-control"
id="subject"
name="subject"
value={formData.subject}
onChange={handleChange}
/>
</div>
<div className="mb-3">
<label htmlFor="message" className="form-label">Message *</label>
<textarea
className="form-control"
id="message"
name="message"
rows={5}
value={formData.message}
onChange={handleChange}
required
></textarea>
</div>
<div className="text-center">
<button
type="submit"
className="btn btn-primary btn-lg"
disabled={loading}
>
{loading ? (
<>
<span className="spinner-border spinner-border-sm me-2" role="status"></span>
Sending...
</>
) : (
'Send Message'
)}
</button>
</div>
</form>
</div>
</div>
</div>
);
}

View File

@@ -1,84 +0,0 @@
'use client';
import { useState, useEffect } from 'react';
export default function ServicesList() {
// Static services data
const services = [
{
id: 1,
title: "Web Development",
description: "Custom web applications built with modern technologies",
slug: "web-development",
icon: "code",
price: 2500,
featured: true,
display_order: 1,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
},
{
id: 2,
title: "Mobile Apps",
description: "Native and cross-platform mobile applications",
slug: "mobile-apps",
icon: "phone",
price: 3500,
featured: false,
display_order: 2,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
}
];
const handleDeleteService = (id: number) => {
if (!confirm('Are you sure you want to delete this service?')) {
return;
}
// Note: This is a demo - in a real app, you'd handle deletion differently
console.log('Service deletion requested for ID:', id);
};
return (
<div className="container py-5">
<div className="row">
<div className="col-12">
<h2 className="mb-4">Our Services</h2>
<div className="row">
{services.map((service) => (
<div key={service.id} className="col-md-6 col-lg-4 mb-4">
<div className="card h-100">
<div className="card-body">
<div className="d-flex justify-content-between align-items-start mb-3">
<h5 className="card-title">{service.title}</h5>
{service.featured && (
<span className="badge bg-primary">Featured</span>
)}
</div>
<p className="card-text">{service.description}</p>
<div className="mt-auto">
<a
href={`/services/${service.slug}`}
className="btn btn-primary me-2"
>
Learn More
</a>
<button
className="btn btn-outline-danger btn-sm"
onClick={() => handleDeleteService(service.id)}
>
Delete
</button>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</div>
);
}

View File

@@ -1,367 +0,0 @@
"use client";
import Image from "next/image";
import Link from "next/link";
import { Swiper, SwiperSlide } from "swiper/react";
import { Autoplay, Navigation } from "swiper/modules";
import "swiper/swiper-bundle.css";
import Counter from "../../common/Counter";
import one from "@/public/images/study/one.png";
import two from "@/public/images/study/two.png";
import three from "@/public/images/study/three.png";
import four from "@/public/images/study/four.png";
import five from "@/public/images/study/five.png";
const AboutCase = () => {
return (
<section className="tp-study pt-120 pb-120 bg-quinary">
<div className="container">
<div className="row vertical-column-gap align-items-center">
<div className="col-12 col-lg-7">
<div className="tp-lp-title text-center text-lg-start">
<div className="enterprise-badge mb-20">
<span className="badge enterprise-badge-content">
<i className="fa-solid fa-chart-line"></i>
Success Stories
</span>
</div>
<h2 className="mt-8 fw-7 text-secondary title-anim">
Enterprise Success Stories
</h2>
<p className="cur-lg mt-20">
Discover how we&apos;ve helped Fortune 500 companies and innovative startups
achieve their digital transformation goals through cutting-edge technology solutions.
</p>
</div>
</div>
<div className="col-12 col-lg-5">
<div className="tp-study-arrows d-flex justify-content-center justify-content-lg-end">
<button className="prev-study" aria-label="previous study">
<span className="material-symbols-outlined">west</span>
</button>
<button className="next-study" aria-label="next study">
<span className="material-symbols-outlined">east</span>
</button>
</div>
</div>
</div>
<div className="row">
<div className="col-12">
<div className="tp-study-slider-wrapper">
<div className="tp-study-slider-wrap">
<Swiper
slidesPerView={"auto"}
spaceBetween={24}
slidesPerGroup={1}
freeMode={true}
speed={1200}
loop={true}
roundLengths={true}
modules={[Autoplay, Navigation]}
autoplay={{
delay: 5000,
disableOnInteraction: false,
pauseOnMouseEnter: true,
}}
className="tp-study-slider"
navigation={{
nextEl: ".prev-study",
prevEl: ".next-study",
}}
>
<SwiperSlide>
<div className="tp-study-slider__single">
<div className="thumb">
<Link href="case-study-single">
<Image
src={one}
className="w-100 mh-400"
alt="Image"
width={400}
height={400}
/>
</Link>
</div>
<div className="content text-center">
<h5 className="mt-8 mb-12 text-white fw-5 text-uppercase">
<Link href="case-study-single">ENTERPRISE CRM</Link>
</h5>
<Link href="case-study-single" className="btn-angle">
View
<span></span>
</Link>
</div>
</div>
</SwiperSlide>
<SwiperSlide>
<div className="tp-study-slider__single">
<div className="thumb">
<Link href="case-study-single">
<Image
src={two}
className="w-100 mh-400"
alt="Image"
width={400}
height={400}
/>
</Link>
</div>
<div className="content text-center">
<h5 className="mt-8 mb-12 text-white fw-5 text-uppercase">
<Link href="case-study-single">ENTERPRISE CRM</Link>
</h5>
<Link href="case-study-single" className="btn-angle">
View
<span></span>
</Link>
</div>
</div>
</SwiperSlide>
<SwiperSlide>
<div className="tp-study-slider__single">
<div className="thumb">
<Link href="case-study-single">
<Image
src={three}
className="w-100 mh-400"
alt="Image"
width={400}
height={400}
/>
</Link>
</div>
<div className="content text-center">
<h5 className="mt-8 mb-12 text-white fw-5 text-uppercase">
<Link href="case-study-single">ENTERPRISE CRM</Link>
</h5>
<Link href="case-study-single" className="btn-angle">
View
<span></span>
</Link>
</div>
</div>
</SwiperSlide>
<SwiperSlide>
<div className="tp-study-slider__single">
<div className="thumb">
<Link href="case-study-single">
<Image
src={four}
className="w-100 mh-400"
alt="Image"
width={400}
height={400}
/>
</Link>
</div>
<div className="content text-center">
<h5 className="mt-8 mb-12 text-white fw-5 text-uppercase">
<Link href="case-study-single">ENTERPRISE CRM</Link>
</h5>
<Link href="case-study-single" className="btn-angle">
View
<span></span>
</Link>
</div>
</div>
</SwiperSlide>
<SwiperSlide>
<div className="tp-study-slider__single">
<div className="thumb">
<Link href="case-study-single">
<Image
src={five}
className="w-100 mh-400"
alt="Image"
width={400}
height={400}
/>
</Link>
</div>
<div className="content text-center">
<h5 className="mt-8 mb-12 text-white fw-5 text-uppercase">
<Link href="case-study-single">ENTERPRISE CRM</Link>
</h5>
<Link href="case-study-single" className="btn-angle">
View
<span></span>
</Link>
</div>
</div>
</SwiperSlide>
<SwiperSlide>
<div className="tp-study-slider__single">
<div className="thumb">
<Link href="case-study-single">
<Image
src={one}
className="w-100 mh-400"
alt="Image"
width={400}
height={400}
/>
</Link>
</div>
<div className="content text-center">
<h5 className="mt-8 mb-12 text-white fw-5 text-uppercase">
<Link href="case-study-single">ENTERPRISE CRM</Link>
</h5>
<Link href="case-study-single" className="btn-angle">
View
<span></span>
</Link>
</div>
</div>
</SwiperSlide>
<SwiperSlide>
<div className="tp-study-slider__single">
<div className="thumb">
<Link href="case-study-single">
<Image
src={two}
className="w-100 mh-400"
alt="Image"
width={400}
height={400}
/>
</Link>
</div>
<div className="content text-center">
<h5 className="mt-8 mb-12 text-white fw-5 text-uppercase">
<Link href="case-study-single">ENTERPRISE CRM</Link>
</h5>
<Link href="case-study-single" className="btn-angle">
View
<span></span>
</Link>
</div>
</div>
</SwiperSlide>
<SwiperSlide>
<div className="tp-study-slider__single">
<div className="thumb">
<Link href="case-study-single">
<Image
src={three}
className="w-100 mh-400"
alt="Image"
width={400}
height={400}
/>
</Link>
</div>
<div className="content text-center">
<h5 className="mt-8 mb-12 text-white fw-5 text-uppercase">
<Link href="case-study-single">ENTERPRISE CRM</Link>
</h5>
<Link href="case-study-single" className="btn-angle">
View
<span></span>
</Link>
</div>
</div>
</SwiperSlide>
<SwiperSlide>
<div className="tp-study-slider__single">
<div className="thumb">
<Link href="case-study-single">
<Image
src={four}
className="w-100 mh-400"
alt="Image"
width={400}
height={400}
/>
</Link>
</div>
<div className="content text-center">
<h5 className="mt-8 mb-12 text-white fw-5 text-uppercase">
<Link href="case-study-single">ENTERPRISE CRM</Link>
</h5>
<Link href="case-study-single" className="btn-angle">
View
<span></span>
</Link>
</div>
</div>
</SwiperSlide>
<SwiperSlide>
<div className="tp-study-slider__single">
<div className="thumb">
<Link href="case-study-single">
<Image
src={five}
className="w-100 mh-400"
alt="Image"
width={400}
height={400}
/>
</Link>
</div>
<div className="content text-center">
<h5 className="mt-8 mb-12 text-white fw-5 text-uppercase">
<Link href="case-study-single">ENTERPRISE CRM</Link>
</h5>
<Link href="case-study-single" className="btn-angle">
View
<span></span>
</Link>
</div>
</div>
</SwiperSlide>
</Swiper>
</div>
</div>
</div>
</div>
<div className="row pt-120 vertical-column-gap-lg">
<div className="col-12 col-sm-6 col-xl-3">
<div className="counter__single text-center">
<h2 className="fw-5 text-secondary mt-8 mb-16">
<span className="odometer">
<Counter value={500} />
</span>
<span>+</span>
</h2>
<p className="text-tertiary">Enterprise Projects</p>
</div>
</div>
<div className="col-12 col-sm-6 col-xl-3">
<div className="counter__single text-center">
<h2 className="fw-5 text-secondary mt-8 mb-16">
<span className="odometer">
<Counter value={99} />
</span>
<span>.9%</span>
</h2>
<p className="text-tertiary">Uptime SLA</p>
</div>
</div>
<div className="col-12 col-sm-6 col-xl-3">
<div className="counter__single text-center">
<h2 className="fw-5 text-secondary mt-8 mb-16">
<span className="odometer">
<Counter value={15} />
</span>
<span>+</span>
</h2>
<p className="text-tertiary">Years Experience</p>
</div>
</div>
<div className="col-12 col-sm-6 col-xl-3">
<div className="counter__single text-center border-0">
<h2 className="fw-5 text-secondary mt-8 mb-16">
<span className="odometer">
<Counter value={200} />
</span>
<span>+</span>
</h2>
<p className="text-tertiary">Expert Engineers</p>
</div>
</div>
</div>
</div>
</section>
);
};
export default AboutCase;

View File

@@ -3,6 +3,7 @@ import Image from "next/image";
import Link from "next/link";
import { useAbout } from "@/lib/hooks/useAbout";
import { AboutService as AboutServiceType, AboutProcess } from "@/lib/api/aboutService";
import { getValidImageUrl, FALLBACK_IMAGES } from "@/lib/imageUtils";
import thumb from "@/public/images/service/two.png";
import thumbTwo from "@/public/images/service/three.png";
@@ -62,13 +63,23 @@ const AboutServiceComponent = () => {
<Link href="service-single" className="w-100">
<div className="parallax-image-wrap">
<div className="parallax-image-inner">
<Image
src={serviceData?.image_url || thumb}
className="w-100 parallax-image"
alt="Enterprise Technology Solutions"
width={400}
height={300}
/>
{serviceData?.image_url ? (
<img
src={getValidImageUrl(serviceData.image_url, FALLBACK_IMAGES.SERVICE)}
className="w-100 parallax-image"
alt="Enterprise Technology Solutions"
width={400}
height={300}
/>
) : (
<Image
src={thumb}
className="w-100 parallax-image"
alt="Enterprise Technology Solutions"
width={400}
height={300}
/>
)}
</div>
</div>
</Link>
@@ -241,13 +252,23 @@ const AboutServiceComponent = () => {
<Link href="service-single" className="w-100">
<div className="parallax-image-wrap">
<div className="parallax-image-inner">
<Image
src={processData?.image_url || thumbTwo}
className="w-100 parallax-image"
alt="Enterprise Development Process"
width={400}
height={300}
/>
{processData?.image_url ? (
<img
src={getValidImageUrl(processData.image_url, FALLBACK_IMAGES.SERVICE)}
className="w-100 parallax-image"
alt="Enterprise Development Process"
width={400}
height={300}
/>
) : (
<Image
src={thumbTwo}
className="w-100 parallax-image"
alt="Enterprise Development Process"
width={400}
height={300}
/>
)}
</div>
</div>
</Link>

View File

@@ -3,6 +3,7 @@ import Image from "next/image";
import Link from "next/link";
import { useAbout } from "@/lib/hooks/useAbout";
import { AboutJourney } from "@/lib/api/aboutService";
import { getValidImageUrl, FALLBACK_IMAGES } from "@/lib/imageUtils";
import thumb from "@/public/images/start-thumb.png";
const AboutStarter = () => {
@@ -52,7 +53,7 @@ const AboutStarter = () => {
const journeyData = data?.journey as AboutJourney | undefined;
return (
<section className="tp-gallery">
<section className="tp-gallery about-compact">
<div className="container">
<div className="row align-items-center">
<div className="col-12 col-lg-6">
@@ -65,7 +66,7 @@ const AboutStarter = () => {
{journeyData?.title || "From Startup to Enterprise Leader"}
</h2>
<p>
{journeyData?.description || "Founded in 2008 by three visionary engineers, Itify Technologies began as a small startup with a big dream: to revolutionize how enterprises approach software development. What started as a passion project has grown into a global enterprise software company serving Fortune 500 clients worldwide."}
{journeyData?.description || "Founded in 2020 by three visionary engineers, GNX Technologies began as a small startup with a big dream: to revolutionize how enterprises approach software development. What started as a passion project has grown into a global enterprise software company serving Fortune 500 clients worldwide."}
</p>
<div className="journey-milestones">
{journeyData?.milestones && journeyData.milestones.length > 0 ? (
@@ -112,7 +113,7 @@ const AboutStarter = () => {
</>
)}
</div>
<div className="mt-4">
<div className="cta-wrap">
<Link
href={journeyData?.cta_link || "services"}
className="btn-line"
@@ -124,26 +125,123 @@ const AboutStarter = () => {
</div>
<div className="col-12 col-lg-6">
<div className="tp-gallery__thumb">
<Image
src={journeyData?.image_url || thumb}
className="w-100"
alt="Enterprise Journey"
width={500}
height={400}
style={{
objectFit: 'contain',
borderRadius: '12px',
boxShadow: '0 20px 40px rgba(0, 0, 0, 0.1)',
maxWidth: '100%',
maxHeight: '500px',
width: '100%',
height: 'auto'
}}
/>
{journeyData?.image_url ? (
<img
src={getValidImageUrl(journeyData.image_url, FALLBACK_IMAGES.DEFAULT)}
className="w-100 compact-img"
alt="Enterprise Journey"
width={500}
height={400}
/>
) : (
<Image
src={thumb}
className="w-100 compact-img"
alt="Enterprise Journey"
width={500}
height={400}
/>
)}
</div>
</div>
</div>
</div>
<style jsx>{`
.about-compact {
padding: 32px 0;
}
/* Typography */
.about-compact .enterprise-badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 4px 10px;
border-radius: 999px;
font-size: 12px;
line-height: 1;
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.08);
color: #fff;
margin-bottom: 10px;
}
.about-compact .enterprise-badge i { font-size: 12px; }
.about-compact .title-anim {
font-size: clamp(20px, 2.2vw, 28px);
line-height: 1.25;
margin: 0 0 8px 0;
}
.about-compact p {
font-size: 14px;
line-height: 1.55;
margin: 0 0 12px 0;
color: rgba(255,255,255,0.85);
}
/* Milestones */
.about-compact .journey-milestones {
display: grid;
grid-template-columns: 1fr;
gap: 10px;
}
@media (min-width: 992px) {
.about-compact .journey-milestones { grid-template-columns: 1fr 1fr; }
}
.about-compact .milestone-item {
display: grid;
grid-template-columns: auto 1fr;
align-items: start;
gap: 10px;
padding: 10px 12px;
border: 1px solid rgba(255,255,255,0.08);
background: rgba(255,255,255,0.03);
border-radius: 10px;
}
.about-compact .year-badge {
display: inline-block;
padding: 4px 8px;
font-size: 12px;
line-height: 1;
border-radius: 6px;
background: rgba(255,255,255,0.08);
color: #fff;
white-space: nowrap;
}
.about-compact .milestone-content h6 {
margin: 0 0 4px 0;
font-size: 14px;
line-height: 1.3;
}
.about-compact .milestone-content p {
margin: 0;
font-size: 13px;
color: rgba(255,255,255,0.75);
}
/* CTA */
.about-compact .cta-wrap { margin-top: 12px; }
.about-compact :global(.btn-line) {
padding: 8px 14px;
font-size: 13px;
line-height: 1;
}
/* Image */
.about-compact .tp-gallery__thumb { margin-top: 8px; }
@media (min-width: 992px) {
.about-compact .tp-gallery__thumb { margin-top: 0; }
}
.about-compact :global(.compact-img),
.about-compact .compact-img {
border-radius: 10px;
box-shadow: 0 8px 24px rgba(0,0,0,0.25);
max-height: 260px;
width: 100%;
height: auto;
object-fit: contain;
}
`}</style>
</section>
);
};

View File

@@ -31,7 +31,6 @@ const PostFilterButtons = ({ handleClick, active }: any) => {
}
if (error) {
console.error('Error loading categories:', error);
// Fallback to showing "All" button only
return (
<div className="row">

View File

@@ -61,7 +61,6 @@ const PostFilterItems = ({ currentPage, onPageChange, onTotalPagesChange, postsP
}
if (error) {
console.error('Error loading posts:', error);
return (
<>
<PostFilterButtons active={active} handleClick={handleCategoryClick} />

File diff suppressed because it is too large Load Diff

View File

@@ -91,11 +91,11 @@ const JobSingle = ({ job }: JobSingleProps) => {
<div className="container">
<div className="row">
<div className="col-12">
<div className="job-header-content" style={{ color: 'white' }}>
<div className="job-header-content" style={{ color: '#ffffff' }}>
<div className="mb-12 mb-md-16">
<span className="badge" style={{
backgroundColor: 'rgba(255,255,255,0.2)',
color: 'white',
color: '#ffffff',
padding: '6px 12px',
borderRadius: '20px',
fontSize: '12px',
@@ -110,7 +110,7 @@ const JobSingle = ({ job }: JobSingleProps) => {
<h1 className="fw-7 mb-16 mb-md-20 mb-lg-24" style={{
fontSize: 'clamp(1.75rem, 5vw, 3.5rem)',
lineHeight: '1.2',
color: 'white'
color: '#ffffff'
}}>
{job.title}
</h1>

View File

@@ -44,13 +44,13 @@ const CaseItems = () => {
<h2 className="mt-8 title-anim fw-7 text-secondary mb-24">
Case Studies
</h2>
<p className="cur-lg">
Lorem ipsum dolor sit amet consectetur. Morbi in non nibh
netus tortor. Non vitae ut consectetur sit quam egestas
praesent. Enim augue cras donec sed pellentesque tortor
maecenas. Tellus duis sit justo neque. Est elit diam quam
venenatis sit morbi sed dignissim eros.
</p>
<p className="cur-lg">
Discover how we help enterprises solve complex challenges with
secure, scalable solutions. Our case studies highlight real
business outcomes accelerated delivery, reduced costs,
improved reliability, and data-driven growth powered by modern
cloud, AI, and platform engineering.
</p>
</div>
</div>
</div>

View File

@@ -93,7 +93,6 @@ const ContactSection = () => {
});
} catch (error) {
console.error('Contact form submission error:', error);
setSubmitStatus({
type: 'error',
message: error instanceof Error ? error.message : 'Failed to submit form. Please try again.'
@@ -413,7 +412,7 @@ const ContactSection = () => {
required
/>
<label htmlFor="privacy">
I agree to the <a href="/privacy-policy">Privacy Policy</a> and consent to being contacted by our team *
I agree to the <a href="/policy?type=privacy">Privacy Policy</a> and consent to being contacted by our team *
</label>
</div>
</div>

View File

@@ -6,18 +6,35 @@ const HomeBanner = () => {
const [currentTextIndex, setCurrentTextIndex] = useState(0);
const [isTransitioning, setIsTransitioning] = useState(false);
// Static banner slides data
// Fix viewport height for mobile browsers (especially iOS Safari)
useEffect(() => {
const setVH = () => {
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
};
setVH();
window.addEventListener('resize', setVH);
window.addEventListener('orientationchange', setVH);
return () => {
window.removeEventListener('resize', setVH);
window.removeEventListener('orientationchange', setVH);
};
}, []);
// Static banner slides data based on actual services
const carouselTexts = [
{
id: 1,
badge: "Enterprise Solutions",
icon: "fa-solid fa-shield-halved",
heading: "Secure Enterprise Software",
badge: "Custom Development",
icon: "fa-solid fa-code",
heading: "Tailored Enterprise Software ",
highlight: "Development",
subheading: "for Modern Businesses",
description: "We build enterprise-grade software solutions with advanced security, scalability, and 24/7 support. Transform your business with our custom development services.",
subheading: "Aligned with Your Business Goals",
description: "We design and build custom digital solutions that deliver reliable, scalable, and future-ready applications, driving measurable value and competitive advantage for your enterprise.",
button_text: "Explore Solutions",
button_url: "/services",
button_url: "/services/custom-software-development",
is_active: true,
display_order: 1,
created_at: new Date().toISOString(),
@@ -25,14 +42,14 @@ const HomeBanner = () => {
},
{
id: 2,
badge: "API Integration",
icon: "fa-solid fa-plug",
heading: "Seamless API",
highlight: "Integration",
subheading: "& System Connectivity",
description: "Connect all your systems with our robust API development and integration services. Enable smooth data flow and unified workflows across your organization.",
button_text: "Learn More",
button_url: "/services/api-development",
badge: "Business Intelligence",
icon: "fa-solid fa-brain",
heading: "AI-Powered ",
highlight: "Analytics",
subheading: "Transform Data into Insights",
description: "Turn enterprise data into actionable intelligence with advanced AI and machine learning, enabling smarter decisions, performance optimization, and data-driven innovation.",
button_text: "Discover AI Solutions",
button_url: "/services/ai-powered-business-intelligence",
is_active: true,
display_order: 2,
created_at: new Date().toISOString(),
@@ -40,18 +57,33 @@ const HomeBanner = () => {
},
{
id: 3,
badge: "Cloud Migration",
icon: "fa-solid fa-cloud",
heading: "Cloud-First",
highlight: "Solutions",
subheading: "for Enterprise Scale",
description: "Migrate to the cloud with confidence. Our cloud solutions provide improved scalability, security, and cost-effectiveness for your enterprise operations.",
button_text: "Start Migration",
button_url: "/services/cloud-solutions",
badge: "System Integration",
icon: "fa-solid fa-plug",
heading: "Enterprise Systems ",
highlight: "Integration",
subheading: "Seamless Connectivity",
description: "Connect everything — from payment systems and ERP platforms to cloud services, enabling your enterprise to operate seamlessly across physical and digital environments.",
button_text: "View Integrations",
button_url: "/services/external-systems-integrations",
is_active: true,
display_order: 3,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
},
{
id: 4,
badge: "Incident Management",
icon: "fa-solid fa-bell",
heading: "Intelligent Incident ",
highlight: "Management",
subheading: "Minimize Downtime & Protect Trust",
description: "Cloud-based incident management that empowers teams to detect, respond, and resolve issues faster, reducing downtime and maintaining customer confidence.",
button_text: "Learn More",
button_url: "/services/incident-management-saas",
is_active: true,
display_order: 4,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
}
];

View File

@@ -1,53 +1,77 @@
import Image from "next/legacy/image";
import Link from "next/link";
import thumb from "@/public/images/service/one.png";
import thumb from "@/public/images/leading.jpg";
const ServiceIntro = () => {
return (
<section className="tp-service pt-120 pb-120">
<div className="container">
<div className="row vertical-column-gap-md">
<div className="col-12 col-lg-5">
<div className="tp-service__thumb fade-img">
<Link href="service-single" className="w-100">
<div className="parallax-image-wrap">
<div className="parallax-image-inner">
<Image
src={thumb}
className="w-100 mh-300 parallax-image"
alt="Image"
/>
</div>
</div>
</Link>
</div>
<div className="container">
<div className="row vertical-column-gap-md">
<div className="col-12 col-lg-4">
<div className="tp-service__thumb" style={{ maxWidth: '400px', border: 'none', padding: 0, margin: 0, overflow: 'hidden', borderRadius: '8px' }}>
<Link href="services">
<Image
src={thumb}
alt="Enterprise Software Solutions"
width={400}
height={500}
objectFit="cover"
style={{ display: 'block', border: 'none', margin: 0, padding: 0 }}
/>
</Link>
</div>
<div className="col-12 col-lg-7 col-xl-6 offset-xl-1">
<div className="tp-service__content">
<h2 className="mt-8 title-anim text-secondary fw-7 mb-30 text-capitalize">
Leading Enterprise Software Solutions Provider.
</div>
<div className="col-12 col-lg-8">
<div className="tp-service__content">
<div className="tp-section-wrapper">
<h2 className="title-anim text-secondary fw-7 mb-30">
Accelerating Digital Transformation Through<br />
Mission-Critical Enterprise Software
</h2>
<div className="pl-100">
<p className="cur-lg">
Transform your enterprise with cutting-edge software solutions,
system integrations, and digital transformation services. We help
Fortune 500 companies modernize their technology infrastructure,
enhance security, and achieve operational excellence through
innovative software development.
</p>
<div className="mt-60">
<Link href="service-single" className="btn-anim btn-anim-light">
Our Solutions
<i className="fa-solid fa-arrow-trend-up"></i>
<span></span>
</Link>
</div>
</div>
<div className="pl-50">
<p className="cur-lg mb-25">
GNX partners with Fortune 40 companies and global enterprises to architect,
develop, and deploy business-critical software solutions that drive measurable
results. Our engineering teams deliver secure, scalable, and compliant systems
that power digital innovation across industries.
</p>
<p className="cur-lg mb-30">
From cloud-native architectures and enterprise integration platforms to
AI-powered analytics and legacy modernization, we provide end-to-end
technology solutions that reduce operational costs, enhance efficiency,
and deliver competitive advantage.
</p>
<div className="tp-service__features mb-40">
<ul className="list-unstyled">
<li className="mb-15">
<i className="fa-solid fa-circle-check text-primary me-10"></i>
<span className="fw-6">Enterprise-Grade Security & Compliance</span>
</li>
<li className="mb-15">
<i className="fa-solid fa-circle-check text-primary me-10"></i>
<span className="fw-6">Scalable Cloud-Native Architectures</span>
</li>
<li className="mb-15">
<i className="fa-solid fa-circle-check text-primary me-10"></i>
<span className="fw-6">24/7 Support & Dedicated Engineering Teams</span>
</li>
</ul>
</div>
<div className="mt-60">
<Link href="services" className="btn-anim btn-anim-light">
Explore Our Solutions
<i className="fa-solid fa-arrow-right"></i>
<span></span>
</Link>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</section>
);
};

View File

@@ -83,7 +83,6 @@ const Story = () => {
// Log when API data is loaded
useEffect(() => {
if (caseStudies.length > 0) {
console.log('Case studies loaded from API:', caseStudies.length);
}
}, [caseStudies]);
@@ -143,11 +142,9 @@ const Story = () => {
// Just filename or relative path
imageUrl = `${API_CONFIG.MEDIA_URL}/${item.thumbnail}`;
}
console.log('Case study image URL:', item.title, '→', imageUrl);
} else {
// Fallback to static image
imageUrl = getValidImageUrl('/images/case/one.png', FALLBACK_IMAGES.CASE_STUDY);
console.log('Using fallback image for:', item.title);
}
return (

View File

@@ -4,8 +4,7 @@ import gsap from "gsap";
import { ScrollTrigger } from "gsap/dist/ScrollTrigger";
import Image from "next/legacy/image";
import Link from "next/link";
import thumbOne from "@/public/images/service/thumb-one.png";
import thumbTwo from "@/public/images/service/thumb-two.png";
const ServicesBanner = () => {
useEffect(() => {
@@ -55,12 +54,12 @@ const ServicesBanner = () => {
<div className="enterprise-banner__content">
<div className="banner-badge mb-4">
<span className="enterprise-badge">
Professional Services
Enterprise Services
</span>
</div>
<h1 className="enterprise-title mb-4">
The end-to-end bespoke software development agency you need
The end-to-end bespoke software development company you need
</h1>
<p className="enterprise-description mb-5">
@@ -106,12 +105,7 @@ const ServicesBanner = () => {
Scroll
<span className="arrow"></span>
</Link>
<div className="thumb-one">
<Image src={thumbOne} alt="Image" width={600} height={400} />
</div>
<div className="thumb-two">
<Image src={thumbTwo} alt="Image" width={600} height={400} />
</div>
</section>
);
};

View File

@@ -55,7 +55,27 @@ const CreateTicketForm = () => {
category: undefined
});
} catch (error: any) {
setSubmitError(error.message || 'Failed to submit ticket. Please try again.');
console.error('Ticket creation error:', error);
// Provide user-friendly error messages based on error type
let errorMessage = 'Failed to submit ticket. Please try again.';
if (error.message) {
if (error.message.includes('email')) {
errorMessage = 'There was an issue with your email address. Please check and try again.';
} else if (error.message.includes('network') || error.message.includes('fetch')) {
errorMessage = 'Network error. Please check your connection and try again.';
} else if (error.message.includes('validation')) {
errorMessage = 'Please check all required fields and try again.';
} else if (error.message.includes('server') || error.message.includes('500')) {
errorMessage = 'Server error. Our team has been notified. Please try again later.';
} else {
// Use the actual error message if it's user-friendly
errorMessage = error.message;
}
}
setSubmitError(errorMessage);
} finally {
setIsSubmitting(false);
}

View File

@@ -28,7 +28,6 @@ const KnowledgeBaseArticleModal = ({ slug, onClose }: KnowledgeBaseArticleModalP
await markArticleHelpful(slug, helpful);
setFeedbackGiven(true);
} catch (error) {
console.error('Error submitting feedback:', error);
}
};

View File

@@ -1,207 +0,0 @@
'use client';
import Image from 'next/image';
import { useState } from 'react';
interface OptimizedImageProps {
src: string;
alt: string;
width?: number;
height?: number;
className?: string;
priority?: boolean;
fill?: boolean;
sizes?: string;
quality?: number;
style?: React.CSSProperties;
objectFit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
loading?: 'lazy' | 'eager';
}
/**
* OptimizedImage Component
*
* An enterprise-grade optimized image component that provides:
* - Automatic lazy loading
* - Responsive images with srcset
* - WebP/AVIF format support
* - Blur placeholder while loading
* - Error handling with fallback
* - Performance optimization
*
* @example
* <OptimizedImage
* src="/images/hero.jpg"
* alt="Hero banner showcasing our services"
* width={1200}
* height={600}
* priority={true}
* />
*/
export default function OptimizedImage({
src,
alt,
width,
height,
className = '',
priority = false,
fill = false,
sizes,
quality = 85,
style,
objectFit = 'cover',
loading,
}: OptimizedImageProps) {
const [imgSrc, setImgSrc] = useState(src);
const [isLoading, setIsLoading] = useState(true);
const [hasError, setHasError] = useState(false);
// Fallback image for errors
const fallbackImage = '/images/placeholder.png';
// Handle image load
const handleLoad = () => {
setIsLoading(false);
};
// Handle image error
const handleError = () => {
setHasError(true);
setIsLoading(false);
if (imgSrc !== fallbackImage) {
setImgSrc(fallbackImage);
}
};
// SEO-friendly alt text validation
const seoAlt = alt || 'GNX Soft - Enterprise Software Solutions';
// Validate alt text for SEO
if (process.env.NODE_ENV === 'development' && !alt) {
console.warn(
`OptimizedImage: Missing alt text for image "${src}". Alt text is crucial for SEO and accessibility.`
);
}
// Common image props
const imageProps = {
src: imgSrc,
alt: seoAlt,
className: `${className} ${isLoading ? 'image-loading' : 'image-loaded'}`,
onLoad: handleLoad,
onError: handleError,
quality,
loading: loading || (priority ? 'eager' : 'lazy'),
style: {
...style,
objectFit: objectFit as any,
},
};
// Use fill layout for responsive images
if (fill) {
return (
<div className={`optimized-image-wrapper ${hasError ? 'has-error' : ''}`}>
<Image
{...imageProps}
fill
sizes={sizes || '100vw'}
priority={priority}
/>
<style jsx>{`
.optimized-image-wrapper {
position: relative;
overflow: hidden;
}
.optimized-image-wrapper.has-error {
background: #f3f4f6;
}
:global(.image-loading) {
filter: blur(10px);
transform: scale(1.1);
transition: filter 0.3s ease, transform 0.3s ease;
}
:global(.image-loaded) {
filter: blur(0);
transform: scale(1);
}
`}</style>
</div>
);
}
// Standard layout with explicit dimensions
return (
<div className={`optimized-image-container ${hasError ? 'has-error' : ''}`}>
<Image
{...imageProps}
width={width}
height={height}
sizes={sizes}
priority={priority}
/>
<style jsx>{`
.optimized-image-container {
position: relative;
display: inline-block;
}
.optimized-image-container.has-error {
background: #f3f4f6;
border-radius: 4px;
}
:global(.image-loading) {
filter: blur(10px);
transform: scale(1.05);
transition: filter 0.4s ease, transform 0.4s ease;
}
:global(.image-loaded) {
filter: blur(0);
transform: scale(1);
}
`}</style>
</div>
);
}
/**
* Usage Examples:
*
* 1. Hero Image (Priority Loading):
* <OptimizedImage
* src="/images/hero.jpg"
* alt="Enterprise software development solutions"
* width={1920}
* height={1080}
* priority={true}
* sizes="100vw"
* />
*
* 2. Service Card Image (Lazy Loading):
* <OptimizedImage
* src="/images/service/custom-software.jpg"
* alt="Custom software development service icon"
* width={400}
* height={300}
* sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
* />
*
* 3. Background Image (Fill):
* <OptimizedImage
* src="/images/background.jpg"
* alt="Technology background pattern"
* fill={true}
* sizes="100vw"
* objectFit="cover"
* />
*
* 4. Logo (High Priority):
* <OptimizedImage
* src="/images/logo.png"
* alt="GNX Soft company logo"
* width={200}
* height={50}
* priority={true}
* quality={100}
* />
*/

View File

@@ -1,57 +0,0 @@
'use client';
import { ReactNode, CSSProperties } from 'react';
interface ProtectedImageProps {
src: string;
alt: string;
className?: string;
style?: CSSProperties;
width?: number;
height?: number;
showWatermark?: boolean;
priority?: boolean;
children?: ReactNode;
}
/**
* Protected Image Component
* Wraps images with protection against downloading and copying
*/
export default function ProtectedImage({
src,
alt,
className = '',
style = {},
width,
height,
showWatermark = false,
children
}: ProtectedImageProps) {
const wrapperClass = `protected-image-wrapper ${showWatermark ? 'watermarked-image' : ''} ${className}`;
return (
<div className={wrapperClass} style={style}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={src}
alt={alt}
width={width}
height={height}
draggable="false"
onContextMenu={(e) => e.preventDefault()}
onDragStart={(e) => e.preventDefault()}
style={{
WebkitUserSelect: 'none',
MozUserSelect: 'none',
msUserSelect: 'none',
userSelect: 'none',
pointerEvents: 'none'
}}
/>
{children}
</div>
);
}

View File

@@ -49,55 +49,116 @@ export const CookieConsentBanner: React.FC = () => {
return (
<AnimatePresence>
{/* Fullscreen overlay to center the banner */}
<motion.div
initial={{ y: 100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 100, opacity: 0 }}
transition={{ duration: 0.3, ease: 'easeOut' }}
className="cookie-consent-banner"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
style={{
position: 'fixed',
inset: 0,
zIndex: 10000,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: 'rgba(17, 24, 39, 0.45)',
backdropFilter: 'blur(4px)',
}}
>
<div className="cookie-consent-banner__container">
<div className="cookie-consent-banner__content">
<div className="cookie-consent-banner__icon">
<i className="fas fa-cookie-bite"></i>
{/* Centered enterprise-style card */}
<motion.div
initial={{ opacity: 0, scale: 0.96, y: 8 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.98, y: 8 }}
transition={{ duration: 0.25, ease: 'easeOut' }}
className="cookie-consent-banner"
style={{
width: 'min(680px, 92vw)',
background: '#0b1220',
color: '#e5e7eb',
border: '1px solid rgba(255,255,255,0.08)',
borderRadius: 16,
boxShadow: '0 25px 70px rgba(0,0,0,0.45)',
padding: 24,
}}
>
<div className="cookie-consent-banner__container" style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<div className="cookie-consent-banner__content" style={{ display: 'flex', gap: 16 }}>
<div
className="cookie-consent-banner__icon"
style={{
width: 48,
height: 48,
borderRadius: 12,
display: 'grid',
placeItems: 'center',
background: 'linear-gradient(135deg, rgba(199, 213, 236, 0.39), rgba(147,197,253,0.08))',
color: '#93c5fd',
flex: '0 0 auto',
}}
>
<i className="fas fa-cookie-bite"></i>
</div>
<div className="cookie-consent-banner__text" style={{ display: 'grid', gap: 6 }}>
<h3 style={{ margin: 0, fontSize: 20, fontWeight: 700 }}>Cookie Preferences</h3>
<p style={{ margin: 0, lineHeight: 1.6, color: '#ffffff' }}>
We use only essential functional cookies to ensure our website works properly. We do not collect
personal data or use tracking cookies. Your privacy is important to us.
</p>
{config.showPrivacyNotice && (
<div className="cookie-consent-banner__links" style={{ marginTop: 6 }}>
<a
href={config.privacyPolicyUrl}
target="_blank"
rel="noopener noreferrer"
style={{ color: '#93c5fd', textDecoration: 'underline' }}
>
Privacy Policy
</a>
</div>
)}
</div>
</div>
<div className="cookie-consent-banner__text">
<h3>Cookie Preferences</h3>
<p>
We use only essential functional cookies to ensure our website works properly.
We do not collect personal data or use tracking cookies. Your privacy is important to us.
</p>
{config.showPrivacyNotice && (
<div className="cookie-consent-banner__links">
<a href={config.privacyPolicyUrl} target="_blank" rel="noopener noreferrer">
Privacy Policy
</a>
<a href={config.cookiePolicyUrl} target="_blank" rel="noopener noreferrer">
Cookie Policy
</a>
</div>
)}
<div
className="cookie-consent-banner__actions"
style={{ display: 'flex', justifyContent: 'flex-end', gap: 12, marginTop: 8 }}
>
<button
type="button"
className="cookie-consent-banner__btn cookie-consent-banner__btn--secondary"
onClick={showSettings}
style={{
padding: '10px 14px',
borderRadius: 10,
border: '1px solid rgba(255,255,255,0.12)',
background: 'transparent',
color: '#e5e7eb',
fontWeight: 600,
}}
>
<i className="fas fa-cog" style={{ marginRight: 8 }}></i>
Settings
</button>
<button
type="button"
className="cookie-consent-banner__btn cookie-consent-banner__btn--primary"
onClick={acceptNecessary}
style={{
padding: '10px 14px',
borderRadius: 10,
border: '1px solid rgba(59,130,246,0.35)',
background: 'linear-gradient(135deg, rgba(59,130,246,0.25), rgba(37,99,235,0.35))',
color: '#ffffff',
fontWeight: 700,
}}
>
<i className="fas fa-check" style={{ marginRight: 8 }}></i>
Accept Functional Only
</button>
</div>
</div>
<div className="cookie-consent-banner__actions">
<button
type="button"
className="cookie-consent-banner__btn cookie-consent-banner__btn--secondary"
onClick={showSettings}
>
<i className="fas fa-cog"></i>
Settings
</button>
<button
type="button"
className="cookie-consent-banner__btn cookie-consent-banner__btn--primary"
onClick={acceptNecessary}
>
<i className="fas fa-check"></i>
Accept Functional Only
</button>
</div>
</div>
</motion.div>
</motion.div>
</AnimatePresence>
);

View File

@@ -64,8 +64,8 @@ const defaultPreferences: CookiePreferences = {
const defaultConfig: CookieConsentConfig = {
version: '2.0',
companyName: 'Your Company Name',
privacyPolicyUrl: '/privacy-policy',
cookiePolicyUrl: '/cookie-policy',
privacyPolicyUrl: '/policy?type=privacy',
cookiePolicyUrl: '/policy?type=privacy',
dataControllerEmail: 'privacy@yourcompany.com',
retentionPeriod: 365, // 1 year
enableAuditLog: true,
@@ -137,7 +137,6 @@ export const CookieConsentProvider: React.FC<{
}
}
} catch (error) {
console.warn('Failed to load cookie preferences:', error);
}
// Show banner if no valid consent found
@@ -171,7 +170,6 @@ export const CookieConsentProvider: React.FC<{
}));
}
} catch (error) {
console.warn('Failed to save cookie preferences:', error);
}
};
@@ -271,7 +269,6 @@ export const CookieConsentProvider: React.FC<{
try {
localStorage.removeItem(CONSENT_STORAGE_KEY);
} catch (error) {
console.warn('Failed to reset cookie preferences:', error);
}
setState({
@@ -288,7 +285,6 @@ export const CookieConsentProvider: React.FC<{
try {
localStorage.removeItem(CONSENT_STORAGE_KEY);
} catch (error) {
console.warn('Failed to withdraw consent:', error);
}
const auditEntry = config.enableAuditLog ? createAuditLogEntry('consent_withdrawn', defaultPreferences) : null;
@@ -386,7 +382,6 @@ export const useFunctional = () => {
try {
localStorage.setItem(`user-preference-${key}`, JSON.stringify(value));
} catch (error) {
console.warn('Failed to save user preference:', error);
}
}
};
@@ -397,7 +392,6 @@ export const useFunctional = () => {
const saved = localStorage.getItem(`user-preference-${key}`);
return saved ? JSON.parse(saved) : defaultValue;
} catch (error) {
console.warn('Failed to load user preference:', error);
return defaultValue;
}
}
@@ -406,7 +400,6 @@ export const useFunctional = () => {
const rememberUserAction = (action: string, data?: any) => {
if (isEnabled) {
console.log('User Action Remembered:', action, data);
// Implement your user action tracking logic here
}
};

View File

@@ -26,7 +26,6 @@ export const useFunctional = () => {
try {
localStorage.setItem(`user-preference-${key}`, JSON.stringify(value));
} catch (error) {
console.warn('Failed to save user preference:', error);
}
}
};
@@ -37,7 +36,6 @@ export const useFunctional = () => {
const saved = localStorage.getItem(`user-preference-${key}`);
return saved ? JSON.parse(saved) : defaultValue;
} catch (error) {
console.warn('Failed to load user preference:', error);
return defaultValue;
}
}
@@ -46,7 +44,6 @@ export const useFunctional = () => {
const rememberUserAction = (action: string, data?: any) => {
if (canShow) {
console.log('User Action Remembered:', action, data);
// Implement your user action tracking logic here
}
};

View File

@@ -24,7 +24,6 @@ const Header = () => {
// Find the Services menu item and update its submenu with API data
const servicesIndex = baseNavigation.findIndex(item => item.title === "Services");
if (servicesIndex !== -1 && apiServices.length > 0) {
console.log('Replacing services with API data:', apiServices);
baseNavigation[servicesIndex] = {
...baseNavigation[servicesIndex],
submenu: apiServices.map(service => ({
@@ -37,8 +36,6 @@ const Header = () => {
updated_at: service.updated_at
}))
} as any;
} else {
console.log('Using static services data. API services:', apiServices.length, 'Services index:', servicesIndex);
}
return baseNavigation;