442 lines
13 KiB
TypeScript
442 lines
13 KiB
TypeScript
"use client";
|
|
import { useSearchParams } from 'next/navigation';
|
|
import { useEffect } from 'react';
|
|
import Header from "@/components/shared/layout/header/Header";
|
|
import Footer from "@/components/shared/layout/footer/Footer";
|
|
import { Suspense } from 'react';
|
|
import { usePolicy } from '@/lib/hooks/usePolicy';
|
|
import { generateMetadata as createMetadata } from "@/lib/seo/metadata";
|
|
|
|
const PolicyContent = () => {
|
|
const searchParams = useSearchParams();
|
|
const typeParam = searchParams.get('type') || 'privacy';
|
|
const type = typeParam as 'privacy' | 'terms' | 'support';
|
|
|
|
const { data: policy, isLoading, error } = usePolicy(type);
|
|
|
|
// Update metadata based on policy type
|
|
useEffect(() => {
|
|
const policyTitles = {
|
|
privacy: 'Privacy Policy - Data Protection & Privacy',
|
|
terms: 'Terms of Use - Terms & Conditions',
|
|
support: 'Support Policy - Support Terms & Guidelines',
|
|
};
|
|
|
|
const policyDescriptions = {
|
|
privacy: 'Read GNX Soft\'s Privacy Policy to understand how we collect, use, and protect your personal information and data.',
|
|
terms: 'Review GNX Soft\'s Terms of Use and Conditions for using our software services and platforms.',
|
|
support: 'Learn about GNX Soft\'s Support Policy, including support terms, response times, and service level agreements.',
|
|
};
|
|
|
|
const metadata = createMetadata({
|
|
title: policyTitles[type],
|
|
description: policyDescriptions[type],
|
|
keywords: [
|
|
type === 'privacy' ? 'Privacy Policy' : type === 'terms' ? 'Terms of Use' : 'Support Policy',
|
|
'Legal Documents',
|
|
'Company Policies',
|
|
'Data Protection',
|
|
'Terms and Conditions',
|
|
],
|
|
url: `/policy?type=${type}`,
|
|
});
|
|
|
|
const titleString = typeof metadata.title === 'string' ? metadata.title : `${policyTitles[type]} | GNX Soft`;
|
|
document.title = titleString;
|
|
|
|
let metaDescription = document.querySelector('meta[name="description"]');
|
|
if (!metaDescription) {
|
|
metaDescription = document.createElement('meta');
|
|
metaDescription.setAttribute('name', 'description');
|
|
document.head.appendChild(metaDescription);
|
|
}
|
|
const descriptionString = typeof metadata.description === 'string' ? metadata.description : policyDescriptions[type];
|
|
metaDescription.setAttribute('content', descriptionString);
|
|
}, [type]);
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<section className="policy-section section-padding">
|
|
<div className="container">
|
|
<div className="row justify-content-center">
|
|
<div className="col-12 col-lg-10">
|
|
<div className="loading-state">
|
|
<div className="spinner"></div>
|
|
<p>Loading policy...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<style jsx>{`
|
|
.policy-section {
|
|
background: linear-gradient(180deg, #f8fafc 0%, #ffffff 100%);
|
|
min-height: 100vh;
|
|
padding: 120px 0 80px;
|
|
}
|
|
|
|
.loading-state {
|
|
text-align: center;
|
|
padding: 4rem 2rem;
|
|
}
|
|
|
|
.spinner {
|
|
width: 50px;
|
|
height: 50px;
|
|
margin: 0 auto 1rem;
|
|
border: 4px solid #f3f3f3;
|
|
border-top: 4px solid #daa520;
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
|
|
@keyframes spin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
|
|
.loading-state p {
|
|
color: #64748b;
|
|
font-size: 1.1rem;
|
|
}
|
|
`}</style>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
if (error || !policy) {
|
|
return (
|
|
<section className="policy-section section-padding">
|
|
<div className="container">
|
|
<div className="row justify-content-center">
|
|
<div className="col-12 col-lg-10">
|
|
<div className="error-state">
|
|
<i className="fa-solid fa-exclamation-circle"></i>
|
|
<h2>Unable to Load Policy</h2>
|
|
<p>{error?.message || 'The requested policy could not be found.'}</p>
|
|
<a href="/support-center" className="btn btn-primary">Return to Support Center</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<style jsx>{`
|
|
.policy-section {
|
|
background: linear-gradient(180deg, #f8fafc 0%, #ffffff 100%);
|
|
min-height: 100vh;
|
|
padding: 120px 0 80px;
|
|
}
|
|
|
|
.error-state {
|
|
text-align: center;
|
|
padding: 4rem 2rem;
|
|
background: #ffffff;
|
|
border-radius: 12px;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.error-state i {
|
|
font-size: 4rem;
|
|
color: #ef4444;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.error-state h2 {
|
|
font-size: 2rem;
|
|
color: #1e293b;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.error-state p {
|
|
color: #64748b;
|
|
font-size: 1.1rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.btn-primary {
|
|
display: inline-block;
|
|
padding: 0.875rem 2rem;
|
|
background: linear-gradient(135deg, #daa520, #d4af37);
|
|
color: #0f172a;
|
|
text-decoration: none;
|
|
border-radius: 8px;
|
|
font-weight: 600;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 10px 25px rgba(218, 165, 32, 0.3);
|
|
}
|
|
`}</style>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<section className="policy-section section-padding">
|
|
<div className="container">
|
|
<div className="row justify-content-center">
|
|
<div className="col-12 col-lg-10">
|
|
{/* Policy Header */}
|
|
<div className="policy-header">
|
|
<h1 className="policy-title">{policy.title}</h1>
|
|
<div className="policy-meta">
|
|
<p className="policy-updated">
|
|
Last Updated: {new Date(policy.last_updated).toLocaleDateString('en-US', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
})}
|
|
</p>
|
|
<p className="policy-version">Version {policy.version}</p>
|
|
<p className="policy-effective">
|
|
Effective Date: {new Date(policy.effective_date).toLocaleDateString('en-US', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
})}
|
|
</p>
|
|
</div>
|
|
{policy.description && (
|
|
<p className="policy-description">{policy.description}</p>
|
|
)}
|
|
</div>
|
|
|
|
{/* Policy Content */}
|
|
<div className="policy-content">
|
|
{policy.sections.map((section) => (
|
|
<div key={section.id} className="policy-section-item">
|
|
<h2 className="policy-heading">{section.heading}</h2>
|
|
<div className="policy-text" dangerouslySetInnerHTML={{
|
|
__html: section.content
|
|
// First, handle main sections with (a), (b), etc.
|
|
.replace(/\(a\)/g, '<br/><br/><strong>(a)</strong>')
|
|
.replace(/\(b\)/g, '<br/><br/><strong>(b)</strong>')
|
|
.replace(/\(c\)/g, '<br/><br/><strong>(c)</strong>')
|
|
.replace(/\(d\)/g, '<br/><br/><strong>(d)</strong>')
|
|
.replace(/\(e\)/g, '<br/><br/><strong>(e)</strong>')
|
|
.replace(/\(f\)/g, '<br/><br/><strong>(f)</strong>')
|
|
.replace(/\(g\)/g, '<br/><br/><strong>(g)</strong>')
|
|
.replace(/\(h\)/g, '<br/><br/><strong>(h)</strong>')
|
|
.replace(/\(i\)/g, '<br/><br/><strong>(i)</strong>')
|
|
.replace(/\(j\)/g, '<br/><br/><strong>(j)</strong>')
|
|
.replace(/\(k\)/g, '<br/><br/><strong>(k)</strong>')
|
|
.replace(/\(l\)/g, '<br/><br/><strong>(l)</strong>')
|
|
// Handle pipe separators for contact information
|
|
.replace(/ \| /g, '<br/><strong>')
|
|
.replace(/: /g, ':</strong> ')
|
|
// Handle semicolon with parenthesis
|
|
.replace(/; \(/g, ';<br/><br/>(')
|
|
// Add spacing after periods in long sentences
|
|
.replace(/\. ([A-Z])/g, '.<br/><br/>$1')
|
|
}} />
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Contact Section */}
|
|
<div className="policy-footer">
|
|
<div className="contact-box">
|
|
<h3>Questions?</h3>
|
|
<p>If you have any questions about this policy, please don't hesitate to contact us.</p>
|
|
<a href="/contact-us" className="btn btn-primary">Contact Us</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style jsx>{`
|
|
.policy-section {
|
|
background: linear-gradient(180deg, #f8fafc 0%, #ffffff 100%);
|
|
min-height: 100vh;
|
|
padding: 120px 0 80px;
|
|
}
|
|
|
|
.policy-header {
|
|
text-align: center;
|
|
margin-bottom: 3rem;
|
|
padding-bottom: 2rem;
|
|
border-bottom: 2px solid #e5e7eb;
|
|
}
|
|
|
|
.policy-title {
|
|
font-size: 2.5rem;
|
|
font-weight: 700;
|
|
color: #0f172a;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.policy-meta {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 2rem;
|
|
flex-wrap: wrap;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.policy-meta p {
|
|
margin: 0;
|
|
}
|
|
|
|
.policy-updated,
|
|
.policy-version,
|
|
.policy-effective {
|
|
color: #64748b;
|
|
font-size: 0.95rem;
|
|
font-style: italic;
|
|
}
|
|
|
|
.policy-version {
|
|
color: #daa520;
|
|
font-weight: 600;
|
|
font-style: normal;
|
|
}
|
|
|
|
.policy-description {
|
|
color: #475569;
|
|
font-size: 1.1rem;
|
|
margin-top: 1rem;
|
|
max-width: 800px;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
}
|
|
|
|
.policy-content {
|
|
margin-bottom: 3rem;
|
|
}
|
|
|
|
.policy-section-item {
|
|
margin-bottom: 2.5rem;
|
|
padding: 2rem;
|
|
background: #ffffff;
|
|
border-radius: 12px;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.policy-section-item:hover {
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.policy-heading {
|
|
font-size: 1.5rem;
|
|
font-weight: 600;
|
|
color: #1e293b;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.policy-text {
|
|
color: #475569;
|
|
font-size: 1rem;
|
|
line-height: 1.8;
|
|
margin: 0;
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
}
|
|
|
|
.policy-text strong {
|
|
color: #1e293b;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.policy-text :global(br) {
|
|
content: "";
|
|
display: block;
|
|
margin: 0.5rem 0;
|
|
}
|
|
|
|
.policy-footer {
|
|
margin-top: 4rem;
|
|
padding-top: 3rem;
|
|
border-top: 2px solid #e5e7eb;
|
|
}
|
|
|
|
.contact-box {
|
|
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
|
|
padding: 3rem;
|
|
border-radius: 12px;
|
|
text-align: center;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.contact-box h3 {
|
|
font-size: 1.75rem;
|
|
margin-bottom: 1rem;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.contact-box p {
|
|
font-size: 1.1rem;
|
|
color: rgba(255, 255, 255, 0.9);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.btn-primary {
|
|
display: inline-block;
|
|
padding: 0.875rem 2rem;
|
|
background: linear-gradient(135deg, #daa520, #d4af37);
|
|
color: #0f172a;
|
|
text-decoration: none;
|
|
border-radius: 8px;
|
|
font-weight: 600;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 10px 25px rgba(218, 165, 32, 0.3);
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.policy-section {
|
|
padding: 100px 0 60px;
|
|
}
|
|
|
|
.policy-title {
|
|
font-size: 2rem;
|
|
}
|
|
|
|
.policy-meta {
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.policy-section-item {
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.policy-heading {
|
|
font-size: 1.25rem;
|
|
}
|
|
|
|
.contact-box {
|
|
padding: 2rem;
|
|
}
|
|
|
|
.contact-box h3 {
|
|
font-size: 1.5rem;
|
|
}
|
|
}
|
|
`}</style>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
const PolicyPage = () => {
|
|
return (
|
|
<div className="tp-app">
|
|
<Header />
|
|
<main>
|
|
<Suspense fallback={<div>Loading...</div>}>
|
|
<PolicyContent />
|
|
</Suspense>
|
|
</main>
|
|
<Footer />
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default PolicyPage;
|
|
|