This commit is contained in:
Iliyan Angelov
2025-10-10 21:54:39 +03:00
parent f962401565
commit 76c857b4f5
49 changed files with 4070 additions and 1353 deletions

View File

@@ -1,4 +1,5 @@
"use client";
import { useEffect } from 'react';
import Header from "@/components/shared/layout/header/Header";
import AboutBanner from "@/components/pages/about/AboutBanner";
import AboutServiceComponent from "@/components/pages/about/AboutService";
@@ -7,7 +8,15 @@ import AboutScrollProgressButton from "@/components/pages/about/AboutScrollProgr
import AboutInitAnimations from "@/components/pages/about/AboutInitAnimations";
import AboutStarter from "@/components/pages/about/AboutStarter";
// Note: Since this is a client component, we'll set metadata via useEffect
const page = () => {
useEffect(() => {
document.title = "About Us - Enterprise Software Development Company | GNX Soft";
const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) {
metaDescription.setAttribute('content', 'Learn about GNX Soft - a leading enterprise software development company with expertise in custom software, data replication, AI business intelligence, and comprehensive IT solutions.');
}
}, []);
return (
<div className="enterprise-about-page">
<Header />

View File

@@ -1,3 +1,4 @@
import { Metadata } from 'next';
import Header from "@/components/shared/layout/header/Header";
import CareerBanner from "@/components/pages/career/CareerBanner";
import OpenPosition from "@/components/pages/career/OpenPosition";
@@ -5,6 +6,21 @@ import Thrive from "@/components/pages/career/Thrive";
import Footer from "@/components/shared/layout/footer/Footer";
import CareerScrollProgressButton from "@/components/pages/career/CareerScrollProgressButton";
import CareerInitAnimations from "@/components/pages/career/CareerInitAnimations";
import { generateMetadata as createMetadata } from "@/lib/seo/metadata";
export const metadata: Metadata = createMetadata({
title: "Careers - Join Our Team",
description: "Explore career opportunities at GNX Soft. Join our team of talented professionals working on cutting-edge enterprise software solutions. View open positions and apply today.",
keywords: [
"Careers",
"Job Openings",
"Software Development Jobs",
"Join Our Team",
"Tech Careers",
"Employment Opportunities",
],
url: "/career",
});
const page = () => {
return (

View File

@@ -1,8 +1,24 @@
import { Metadata } from 'next';
import Header from "@/components/shared/layout/header/Header";
import CaseItems from "@/components/pages/case-study/CaseItems";
import Footer from "@/components/shared/layout/footer/Footer";
import CaseStudyScrollProgressButton from "@/components/pages/case-study/CaseStudyScrollProgressButton";
import CaseStudyInitAnimations from "@/components/pages/case-study/CaseStudyInitAnimations";
import { generateMetadata as createMetadata } from "@/lib/seo/metadata";
export const metadata: Metadata = createMetadata({
title: "Case Studies - Success Stories & Client Projects",
description: "Explore our case studies showcasing successful enterprise software development projects, client success stories, and real-world implementations of our technology solutions.",
keywords: [
"Case Studies",
"Success Stories",
"Client Projects",
"Software Development Portfolio",
"Enterprise Solutions Examples",
"Client Testimonials",
],
url: "/case-study",
});
const page = () => {
return (

View File

@@ -1,8 +1,23 @@
import { Metadata } from 'next';
import Header from "@/components/shared/layout/header/Header";
import ContactSection from "@/components/pages/contact/ContactSection";
import Footer from "@/components/shared/layout/footer/Footer";
import ContactScrollProgressButton from "@/components/pages/contact/ContactScrollProgressButton";
import ContactInitAnimations from "@/components/pages/contact/ContactInitAnimations";
import { generateMetadata as createMetadata } from "@/lib/seo/metadata";
export const metadata: Metadata = createMetadata({
title: "Contact Us - Get in Touch with Our Team",
description: "Contact GNX Soft for enterprise software development solutions. Get a free consultation, discuss your project requirements, or request a quote for our services.",
keywords: [
"Contact GNX Soft",
"Software Development Quote",
"Enterprise Solutions Consultation",
"Custom Software Inquiry",
"Get in Touch",
],
url: "/contact-us",
});
const page = () => {
return (

View File

@@ -1,8 +1,24 @@
import { Metadata } from 'next';
import Header from "@/components/shared/layout/header/Header";
import BlogItems from "@/components/pages/blog/BlogItems";
import Footer from "@/components/shared/layout/footer/Footer";
import BlogScrollProgressButton from "@/components/pages/blog/BlogScrollProgressButton";
import BlogInitAnimations from "@/components/pages/blog/BlogInitAnimations";
import { generateMetadata as createMetadata } from "@/lib/seo/metadata";
export const metadata: Metadata = createMetadata({
title: "Insights & Blog - Technology Trends & Best Practices",
description: "Stay updated with the latest insights on enterprise software development, technology trends, best practices, and industry news from GNX Soft's expert team.",
keywords: [
"Technology Blog",
"Software Development Insights",
"Tech Trends",
"Enterprise Software Blog",
"Development Best Practices",
"Industry News",
],
url: "/insights",
});
const page = () => {
return (

View File

@@ -4,6 +4,8 @@ import "@/public/styles/main.scss";
import { CookieConsentProvider } from "@/components/shared/layout/CookieConsentContext";
import { CookieConsent } from "@/components/shared/layout/CookieConsent";
import LayoutWrapper from "@/components/shared/layout/LayoutWrapper";
import { generateMetadata as createMetadata } from "@/lib/seo/metadata";
import { OrganizationSchema, WebsiteSchema, LocalBusinessSchema } from "@/components/shared/seo/StructuredData";
const montserrat = Montserrat({
subsets: ["latin"],
@@ -37,26 +39,22 @@ const inter = Inter({
],
});
export const metadata: Metadata = {
title: "EnterpriseSoft Solutions | Enterprise Software Development & IT Solutions",
description: "Leading enterprise software development company providing custom solutions, system integrations, and digital transformation services for Fortune 500 companies",
// Enhanced SEO metadata for root layout
export const metadata: Metadata = createMetadata({
title: "Enterprise Software Development & IT Solutions",
description: "Leading enterprise software development company specializing in custom software, data replication, incident management, AI business intelligence, and comprehensive system integrations for modern businesses.",
keywords: [
"Enterprise Software",
"Custom Development",
"System Integration",
"Digital Transformation",
"Enterprise Solutions",
"Software Consulting",
"API Development",
"Cloud Migration",
"Enterprise Software Development",
"Custom Software Solutions",
"Data Replication Services",
"Incident Management SaaS",
"AI Business Intelligence",
"Backend Engineering",
"Frontend Engineering",
"Systems Integration",
],
authors: [
{
name: "EnterpriseSoft Solutions",
url: "https://enterprisesoft.com",
},
],
};
url: "/",
});
export default function RootLayout({
children,
@@ -76,14 +74,85 @@ export default function RootLayout({
`,
}}
/>
{/* Content Protection Script */}
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
if (typeof window === 'undefined') return;
// Wait for DOM to be ready
document.addEventListener('DOMContentLoaded', function() {
// Disable right-click
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
return false;
});
// Disable keyboard shortcuts
document.addEventListener('keydown', function(e) {
// Ctrl+C, Ctrl+X, Ctrl+S, Ctrl+A, Ctrl+P, Ctrl+U, Ctrl+I, Ctrl+J
if ((e.ctrlKey || e.metaKey) && ['c','x','s','a','p','u','i','j','k'].includes(e.key)) {
e.preventDefault();
return false;
}
// F12
if (e.key === 'F12' || e.keyCode === 123) {
e.preventDefault();
return false;
}
// Ctrl+Shift+I, Ctrl+Shift+J, Ctrl+Shift+C
if ((e.ctrlKey || e.metaKey) && e.shiftKey && ['I','J','C'].includes(e.key)) {
e.preventDefault();
return false;
}
});
// Disable text selection
document.addEventListener('selectstart', function(e) {
if (e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA') {
e.preventDefault();
return false;
}
});
// Disable image dragging
document.addEventListener('dragstart', function(e) {
e.preventDefault();
return false;
});
// Disable copy/cut
document.addEventListener('copy', function(e) {
e.preventDefault();
return false;
});
document.addEventListener('cut', function(e) {
e.preventDefault();
return false;
});
// Console warning
console.log('%cSTOP!', 'color: red; font-size: 40px; font-weight: bold;');
console.log('%c© GNX Soft - All Rights Reserved', 'font-size: 14px;');
});
})();
`,
}}
/>
</head>
<body className={`${inter.variable} ${montserrat.variable}`} style={{ scrollBehavior: 'auto', overflow: 'auto' }}>
<body className={`${inter.variable} ${montserrat.variable} content-protected`} style={{ scrollBehavior: 'auto', overflow: 'auto' }}>
{/* Structured Data for SEO */}
<OrganizationSchema />
<WebsiteSchema />
<LocalBusinessSchema />
<CookieConsentProvider
config={{
companyName: "EnterpriseSoft Solutions",
privacyPolicyUrl: "/privacy-policy",
cookiePolicyUrl: "/cookie-policy",
dataControllerEmail: "privacy@enterprisesoft.com",
companyName: "GNX Soft",
privacyPolicyUrl: "/policy",
cookiePolicyUrl: "/policy",
dataControllerEmail: "privacy@gnxsoft.com",
retentionPeriod: 365,
enableAuditLog: true,
enableDetailedSettings: true,

35
gnx-react/app/robots.ts Normal file
View File

@@ -0,0 +1,35 @@
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://gnxsoft.com';
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: [
'/api/',
'/admin/',
'/_next/',
'/private/',
'/*.json$',
'/*?*',
],
},
{
userAgent: 'Googlebot',
allow: '/',
disallow: ['/api/', '/admin/', '/private/'],
},
{
userAgent: 'Bingbot',
allow: '/',
disallow: ['/api/', '/admin/', '/private/'],
},
],
sitemap: `${baseUrl}/sitemap.xml`,
host: baseUrl,
};
}

View File

@@ -10,6 +10,8 @@ import Footer from "@/components/shared/layout/footer/Footer";
import ServicesScrollProgressButton from "@/components/pages/services/ServicesScrollProgressButton";
import ServicesInitAnimations from "@/components/pages/services/ServicesInitAnimations";
import { serviceService, Service } from "@/lib/api/serviceService";
import { generateServiceMetadata } from "@/lib/seo/metadata";
import { ServiceSchema, BreadcrumbSchema } from "@/components/shared/seo/StructuredData";
interface ServicePageProps {
params: Promise<{
@@ -30,21 +32,13 @@ export async function generateStaticParams() {
}
}
// Generate metadata for each service page
// Generate enhanced metadata for each service page
export async function generateMetadata({ params }: ServicePageProps) {
try {
const { slug } = await params;
const service = await serviceService.getServiceBySlug(slug);
return {
title: `${service.title} - GNX Services`,
description: service.description,
openGraph: {
title: service.title,
description: service.description,
images: service.image_url ? [service.image_url] : [],
},
};
return generateServiceMetadata(service);
} catch (error) {
return {
title: 'Service Not Found - GNX',
@@ -64,8 +58,19 @@ const ServicePage = async ({ params }: ServicePageProps) => {
notFound();
}
// Breadcrumb data for structured data
const breadcrumbItems = [
{ name: 'Home', url: '/' },
{ name: 'Services', url: '/services' },
{ name: service.title, url: `/services/${service.slug}` },
];
return (
<div className="enterprise-app">
{/* SEO Structured Data */}
<ServiceSchema service={service} />
<BreadcrumbSchema items={breadcrumbItems} />
<Header />
<main className="enterprise-main">
<ServiceDetailsBanner service={service} />

View File

@@ -1,9 +1,27 @@
import { Metadata } from 'next';
import Header from "@/components/shared/layout/header/Header";
import ServicesBanner from "@/components/pages/services/ServicesBanner";
import ServiceMain from "@/components/pages/services/ServiceMain";
import Footer from "@/components/shared/layout/footer/Footer";
import ServicesScrollProgressButton from "@/components/pages/services/ServicesScrollProgressButton";
import ServicesInitAnimations from "@/components/pages/services/ServicesInitAnimations";
import { generateMetadata as createMetadata } from "@/lib/seo/metadata";
export const metadata: Metadata = createMetadata({
title: "Our Services - Enterprise Software Development",
description: "Explore our comprehensive range of enterprise software development services including custom software, data replication, incident management, AI business intelligence, backend & frontend engineering, and systems integration.",
keywords: [
"Software Development Services",
"Custom Software Development",
"Data Replication",
"Incident Management SaaS",
"AI Business Intelligence",
"Backend Engineering Services",
"Frontend Development",
"Systems Integration Services",
],
url: "/services",
});
const page = () => {
return (

137
gnx-react/app/sitemap.ts Normal file
View File

@@ -0,0 +1,137 @@
import { MetadataRoute } from 'next';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://gnxsoft.com';
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api';
// Static pages
const staticPages: MetadataRoute.Sitemap = [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 1.0,
},
{
url: `${baseUrl}/about-us`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.9,
},
{
url: `${baseUrl}/services`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.9,
},
{
url: `${baseUrl}/case-study`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.8,
},
{
url: `${baseUrl}/insights`,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 0.8,
},
{
url: `${baseUrl}/career`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.7,
},
{
url: `${baseUrl}/contact-us`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/support-center`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.7,
},
{
url: `${baseUrl}/policy`,
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 0.5,
},
];
try {
// Fetch dynamic services
const servicesResponse = await fetch(`${apiUrl}/services/`, {
next: { revalidate: 3600 }, // Revalidate every hour
});
let servicePages: MetadataRoute.Sitemap = [];
if (servicesResponse.ok) {
const services = await servicesResponse.json();
servicePages = services.map((service: any) => ({
url: `${baseUrl}/services/${service.slug}`,
lastModified: new Date(service.updated_at || service.created_at),
changeFrequency: 'weekly' as const,
priority: service.featured ? 0.9 : 0.7,
}));
}
// Fetch dynamic blog posts
const blogResponse = await fetch(`${apiUrl}/blog/`, {
next: { revalidate: 3600 },
});
let blogPages: MetadataRoute.Sitemap = [];
if (blogResponse.ok) {
const posts = await blogResponse.json();
blogPages = posts.map((post: any) => ({
url: `${baseUrl}/insights/${post.slug}`,
lastModified: new Date(post.updated_at || post.published_at),
changeFrequency: 'weekly' as const,
priority: 0.7,
}));
}
// Fetch dynamic case studies
const caseStudiesResponse = await fetch(`${apiUrl}/case-studies/`, {
next: { revalidate: 3600 },
});
let caseStudyPages: MetadataRoute.Sitemap = [];
if (caseStudiesResponse.ok) {
const caseStudies = await caseStudiesResponse.json();
caseStudyPages = caseStudies.map((study: any) => ({
url: `${baseUrl}/case-study/${study.slug}`,
lastModified: new Date(study.updated_at || study.created_at),
changeFrequency: 'monthly' as const,
priority: 0.7,
}));
}
// Fetch dynamic career postings
const careerResponse = await fetch(`${apiUrl}/career/positions/`, {
next: { revalidate: 3600 },
});
let careerPages: MetadataRoute.Sitemap = [];
if (careerResponse.ok) {
const positions = await careerResponse.json();
careerPages = positions.map((position: any) => ({
url: `${baseUrl}/career/${position.slug}`,
lastModified: new Date(position.updated_at || position.created_at),
changeFrequency: 'weekly' as const,
priority: 0.6,
}));
}
return [...staticPages, ...servicePages, ...blogPages, ...caseStudyPages, ...careerPages];
} catch (error) {
console.error('Error generating sitemap:', error);
// Return at least static pages if API fails
return staticPages;
}
}