![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.quebec/private_html/src/components/ |
import Head from 'next/head';
// Base interface for structured data
interface BaseStructuredData {
'@context': string;
'@type': string;
}
// Legal Case structured data
interface LegalCaseStructuredData extends BaseStructuredData {
'@type': 'LegalCase';
name: string;
description: string;
url: string;
dateCreated: string;
dateModified: string;
datePublished: string;
author?: {
'@type': 'Person' | 'Organization';
name: string;
url?: string;
};
publisher: {
'@type': 'Organization';
name: string;
url: string;
logo?: {
'@type': 'ImageObject';
url: string;
};
};
mainEntityOfPage?: {
'@type': 'WebPage';
'@id': string;
};
image?: {
'@type': 'ImageObject';
url: string;
width?: number;
height?: number;
};
category?: string;
legalArea?: string;
jurisdiction?: string;
court?: string;
status?: string;
urgencyLevel?: string;
riskLevel?: string;
estimatedValue?: number;
tags?: string[];
commentCount?: number;
viewCount?: number;
supporterCount?: number;
}
// Lawyer/Person structured data
interface LawyerStructuredData extends BaseStructuredData {
'@type': 'Person';
name: string;
url: string;
image?: string;
description?: string;
jobTitle?: string;
worksFor?: {
'@type': 'Organization';
name: string;
url?: string;
};
address?: {
'@type': 'PostalAddress';
addressLocality?: string;
addressRegion?: string;
addressCountry?: string;
};
telephone?: string;
email?: string;
sameAs?: string[];
alumniOf?: {
'@type': 'Organization';
name: string;
};
knowsAbout?: string[];
hasCredential?: {
'@type': 'EducationalOccupationalCredential';
name: string;
credentialCategory: string;
}[];
award?: string[];
review?: {
'@type': 'Review';
reviewRating: {
'@type': 'Rating';
ratingValue: number;
bestRating: number;
};
author: {
'@type': 'Person';
name: string;
};
}[];
aggregateRating?: {
'@type': 'AggregateRating';
ratingValue: number;
reviewCount: number;
bestRating: number;
};
priceRange?: string;
areaServed?: {
'@type': 'Place';
name: string;
}[];
availableService?: {
'@type': 'Service';
name: string;
description: string;
}[];
}
// Organization structured data
interface OrganizationStructuredData extends BaseStructuredData {
'@type': 'Organization';
name: string;
url: string;
logo?: {
'@type': 'ImageObject';
url: string;
width?: number;
height?: number;
};
description?: string;
address?: {
'@type': 'PostalAddress';
streetAddress?: string;
addressLocality?: string;
addressRegion?: string;
postalCode?: string;
addressCountry?: string;
};
contactPoint?: {
'@type': 'ContactPoint';
telephone?: string;
email?: string;
contactType: string;
}[];
sameAs?: string[];
founder?: {
'@type': 'Person';
name: string;
}[];
employee?: {
'@type': 'Person';
name: string;
jobTitle: string;
}[];
serviceArea?: {
'@type': 'Place';
name: string;
}[];
areaServed?: {
'@type': 'Place';
name: string;
}[];
}
// Article structured data
interface ArticleStructuredData extends BaseStructuredData {
'@type': 'Article';
headline: string;
description: string;
url: string;
datePublished: string;
dateModified: string;
author: {
'@type': 'Person' | 'Organization';
name: string;
url?: string;
};
publisher: {
'@type': 'Organization';
name: string;
url: string;
logo?: {
'@type': 'ImageObject';
url: string;
};
};
mainEntityOfPage?: {
'@type': 'WebPage';
'@id': string;
};
image?: {
'@type': 'ImageObject';
url: string;
width?: number;
height?: number;
};
articleSection?: string;
keywords?: string;
wordCount?: number;
timeRequired?: string;
}
// WebSite structured data
interface WebSiteStructuredData extends BaseStructuredData {
'@type': 'WebSite';
name: string;
url: string;
description?: string;
publisher?: {
'@type': 'Organization';
name: string;
url: string;
};
potentialAction?: {
'@type': 'SearchAction';
target: {
'@type': 'EntryPoint';
urlTemplate: string;
};
'query-input': string;
};
}
// BreadcrumbList structured data
interface BreadcrumbStructuredData extends BaseStructuredData {
'@type': 'BreadcrumbList';
itemListElement: {
'@type': 'ListItem';
position: number;
name: string;
item: string;
}[];
}
// FAQ structured data
interface FAQStructuredData extends BaseStructuredData {
'@type': 'FAQPage';
mainEntity: {
'@type': 'Question';
name: string;
acceptedAnswer: {
'@type': 'Answer';
text: string;
};
}[];
}
// HowTo structured data
interface HowToStructuredData extends BaseStructuredData {
'@type': 'HowTo';
name: string;
description: string;
image?: {
'@type': 'ImageObject';
url: string;
};
totalTime?: string;
estimatedCost?: {
'@type': 'MonetaryAmount';
currency: string;
value: string;
};
supply?: {
'@type': 'HowToSupply';
name: string;
}[];
tool?: {
'@type': 'HowToTool';
name: string;
}[];
step: {
'@type': 'HowToStep';
name: string;
text: string;
url?: string;
image?: {
'@type': 'ImageObject';
url: string;
};
}[];
}
// Props for the component
interface StructuredDataProps {
type: 'legalCase' | 'lawyer' | 'organization' | 'article' | 'website' | 'breadcrumb' | 'faq' | 'howTo';
data: LegalCaseStructuredData | LawyerStructuredData | OrganizationStructuredData | ArticleStructuredData | WebSiteStructuredData | BreadcrumbStructuredData | FAQStructuredData | HowToStructuredData;
}
const StructuredData: React.FC<StructuredDataProps> = ({ type, data }) => {
return (
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(data, null, 2)
}}
/>
</Head>
);
};
// Helper functions to create structured data objects
export const createLegalCaseStructuredData = (caseData: any): LegalCaseStructuredData => {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://15.235.50.60:3000';
return {
'@context': 'https://schema.org',
'@type': 'LegalCase',
name: caseData.title || 'Legal Case',
description: caseData.description || caseData.summary || 'Legal case details and information',
url: baseUrl + '/public/cases/' + caseData.id,
dateCreated: caseData.createdAt,
dateModified: caseData.updatedAt,
datePublished: caseData.createdAt,
author: caseData.client ? {
'@type': 'Person',
name: caseData.client.name,
url: caseData.client.username ? baseUrl + '/profile/' + caseData.client.username : undefined
} : caseData.lawyer ? {
'@type': 'Person',
name: caseData.lawyer.name,
url: caseData.lawyer.username ? baseUrl + '/profile/' + caseData.lawyer.username : undefined
} : undefined,
publisher: {
'@type': 'Organization',
name: 'Liberté Même en Prison',
url: baseUrl,
logo: {
'@type': 'ImageObject',
url: baseUrl + '/images/logo.png'
}
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': baseUrl + '/public/cases/' + caseData.id
},
image: caseData.client?.profileImage ? {
'@type': 'ImageObject',
url: caseData.client.profileImage.startsWith('http') ? caseData.client.profileImage : baseUrl + caseData.client.profileImage,
width: 1200,
height: 630
} : undefined,
category: caseData.category,
legalArea: caseData.legalArea,
jurisdiction: caseData.jurisdiction,
court: caseData.court,
status: caseData.status,
urgencyLevel: caseData.urgencyLevel,
riskLevel: caseData.riskLevel,
estimatedValue: caseData.estimatedValue,
tags: caseData.tags,
commentCount: caseData._count?.comments || 0,
viewCount: caseData.viewCount || 0,
supporterCount: caseData.supporterCount || 0
};
};
export const createLawyerStructuredData = (lawyerData: any): LawyerStructuredData => {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://15.235.50.60:3000';
return {
'@context': 'https://schema.org',
'@type': 'Person',
name: lawyerData.name,
url: baseUrl + '/profile/' + lawyerData.username,
image: lawyerData.profilePicture ?
(lawyerData.profilePicture.startsWith('http') ? lawyerData.profilePicture : baseUrl + lawyerData.profilePicture) :
undefined,
description: lawyerData.bio,
jobTitle: lawyerData.title || 'Lawyer',
worksFor: {
'@type': 'Organization',
name: 'Liberté Même en Prison',
url: baseUrl
},
address: lawyerData.officeLocation ? {
'@type': 'PostalAddress',
addressLocality: lawyerData.officeLocation
} : undefined,
telephone: lawyerData.workPhone,
email: lawyerData.email,
sameAs: [
lawyerData.linkedinUrl,
lawyerData.websiteUrl
].filter(Boolean),
knowsAbout: [
lawyerData.specialization,
'Legal Services',
'Law'
].filter(Boolean),
hasCredential: lawyerData.education ? [{
'@type': 'EducationalOccupationalCredential',
name: lawyerData.education,
credentialCategory: 'Educational Credential'
}] : undefined,
award: lawyerData.isVerified ? ['Verified Lawyer'] : undefined,
aggregateRating: lawyerData.averageRating ? {
'@type': 'AggregateRating',
ratingValue: lawyerData.averageRating,
reviewCount: lawyerData.totalCases || 0,
bestRating: 5
} : undefined,
priceRange: lawyerData.hourlyRate ? '$' + lawyerData.hourlyRate + '/hour' : undefined,
areaServed: lawyerData.officeLocation ? [{
'@type': 'Place',
name: lawyerData.officeLocation
}] : undefined,
availableService: [{
'@type': 'Service',
name: 'Legal Consultation',
description: 'Professional legal consultation and representation services'
}]
};
};
export const createOrganizationStructuredData = (): OrganizationStructuredData => {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://15.235.50.60:3000';
return {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Liberté Même en Prison',
url: baseUrl,
logo: {
'@type': 'ImageObject',
url: baseUrl + '/images/logo.png',
width: 180,
height: 180
},
description: 'A comprehensive legal marketplace connecting clients with qualified legal professionals. Browse cases, find lawyers, and access legal services.',
contactPoint: [
{
'@type': 'ContactPoint',
contactType: 'customer service',
email: 'support@libertememeenprison.com'
}
],
sameAs: [
'https://twitter.com/LiberteMemeEnPrison',
'https://linkedin.com/company/libertememeenprison'
],
serviceArea: [
{
'@type': 'Place',
name: 'Global'
}
]
};
};
export const createArticleStructuredData = (articleData: any): ArticleStructuredData => {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://15.235.50.60:3000';
return {
'@context': 'https://schema.org',
'@type': 'Article',
headline: articleData.title,
description: articleData.description || articleData.summary,
url: baseUrl + articleData.url,
datePublished: articleData.createdAt,
dateModified: articleData.updatedAt,
author: {
'@type': 'Person',
name: articleData.author || 'Liberté Même en Prison',
url: articleData.authorUrl
},
publisher: {
'@type': 'Organization',
name: 'Liberté Même en Prison',
url: baseUrl,
logo: {
'@type': 'ImageObject',
url: baseUrl + '/images/logo.png',
}
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': baseUrl + articleData.url
},
image: articleData.image ? {
'@type': 'ImageObject',
url: articleData.image.startsWith('http') ? articleData.image : baseUrl + articleData.image,
width: 1200,
height: 630
} : undefined,
articleSection: articleData.section || 'Legal Services',
keywords: articleData.tags?.join(', ') || 'legal, law, justice',
wordCount: articleData.content?.length || 0
};
};
export const createWebSiteStructuredData = (): WebSiteStructuredData => {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://15.235.50.60:3000';
return {
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'Liberté Même en Prison',
url: baseUrl,
description: 'A comprehensive legal marketplace connecting clients with qualified legal professionals',
publisher: {
'@type': 'Organization',
name: 'Liberté Même en Prison',
url: baseUrl
},
potentialAction: {
'@type': 'SearchAction',
target: {
'@type': 'EntryPoint',
urlTemplate: baseUrl + '/search?q={search_term_string}',
},
'query-input': 'required name=search_term_string'
}
};
};
export const createBreadcrumbStructuredData = (breadcrumbs: Array<{ name: string; url: string }>): BreadcrumbStructuredData => {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://15.235.50.60:3000';
return {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: breadcrumbs.map((breadcrumb, index) => ({
'@type': 'ListItem',
position: index + 1,
name: breadcrumb.name,
item: breadcrumb.url.startsWith('http') ? breadcrumb.url : baseUrl + breadcrumb.url
}))
};
};
export const createFAQStructuredData = (faqs: Array<{ question: string; answer: string }>): FAQStructuredData => {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://15.235.50.60:3000';
return {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: faqs.map(faq => ({
'@type': 'Question',
name: faq.question,
acceptedAnswer: {
'@type': 'Answer',
text: faq.answer
}
}))
};
};
export const createHowToStructuredData = (howToData: {
name: string;
description: string;
steps: Array<{ name: string; text: string; url?: string; image?: string }>;
totalTime?: string;
estimatedCost?: { currency: string; value: string };
supply?: string[];
tool?: string[];
image?: string;
}): HowToStructuredData => {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://15.235.50.60:3000';
return {
'@context': 'https://schema.org',
'@type': 'HowTo',
name: howToData.name,
description: howToData.description,
image: howToData.image ? {
'@type': 'ImageObject',
url: howToData.image.startsWith('http') ? howToData.image : baseUrl + howToData.image
} : undefined,
totalTime: howToData.totalTime,
estimatedCost: howToData.estimatedCost ? {
'@type': 'MonetaryAmount',
currency: howToData.estimatedCost.currency,
value: howToData.estimatedCost.value
} : undefined,
supply: howToData.supply?.map(item => ({
'@type': 'HowToSupply',
name: item
})),
tool: howToData.tool?.map(item => ({
'@type': 'HowToTool',
name: item
})),
step: howToData.steps.map((step, index) => ({
'@type': 'HowToStep',
name: step.name,
text: step.text,
url: step.url ? (step.url.startsWith('http') ? step.url : baseUrl + step.url) : undefined,
image: step.image ? {
'@type': 'ImageObject',
url: step.image.startsWith('http') ? step.image : baseUrl + step.image
} : undefined
}))
};
};
export default StructuredData;