Function bodies 202 total
Article function · typescript · L1-L7 (7 LOC)src/data/blog/articles/perfect-3-day-paris-itinerary/pt.tsx
export default function Article() {
return (
<article>
<p>[Article content in pt - To be completed]</p>
</article>
)
}Article function · typescript · L1-L112 (112 LOC)src/data/blog/articles/vtc-vs-taxi-vs-uber-paris/es.tsx
export default function Article() {
return (
<article>
<p>
¿Planificando tu traslado al aeropuerto de París y confundido sobre si reservar un VTC, tomar un taxi o usar Uber?
En esta guía completa, compararemos las tres opciones principales de transporte en París para ayudarte a tomar la mejor decisión.
</p>
<h2>¿Qué es VTC?</h2>
<p>
VTC significa "Voiture de Transport avec Chauffeur" (Vehículo de Transporte con Chofer). Es un servicio
de chofer privado con licencia en Francia, similar a los servicios ejecutivos de automóviles.
</p>
<h3>Características del VTC:</h3>
<ul>
<li>Servicio pre-reservado con precios fijos garantizados</li>
<li>Choferes profesionales con licencia</li>
<li>Vehículos premium (Mercedes, BMW)</li>
<li>Servicio de recepción en aeropuertos con cartel</li>
<li>Monitoreo de vuelo incluido sin cargo extra</li>
<li>Sin precios dinámicos ni sorArticle function · typescript · L1-L112 (112 LOC)src/data/blog/articles/vtc-vs-taxi-vs-uber-paris/fr.tsx
export default function Article() {
return (
<article>
<p>
Vous planifiez votre transfert aéroport à Paris et vous hésitez entre réserver un VTC, prendre un taxi ou utiliser Uber ?
Dans ce guide complet, nous comparerons les trois principales options de transport à Paris pour vous aider à prendre la meilleure décision.
</p>
<h2>Qu'est-ce qu'un VTC ?</h2>
<p>
VTC signifie "Voiture de Transport avec Chauffeur". C'est un service de chauffeur privé avec licence en France,
similaire aux services de voitures exécutives.
</p>
<h3>Caractéristiques du VTC :</h3>
<ul>
<li>Service pré-réservé avec prix fixes garantis</li>
<li>Chauffeurs professionnels avec licence</li>
<li>Véhicules premium (Mercedes, BMW)</li>
<li>Service d'accueil à l'aéroport avec pancarte</li>
<li>Suivi de vol inclus sans frais supplémentaires</li>
<li>Pas de tarification dynamique ni de surprises<Article function · typescript · L1-L112 (112 LOC)src/data/blog/articles/vtc-vs-taxi-vs-uber-paris/pt.tsx
export default function Article() {
return (
<article>
<p>
Planejando sua transferência do aeroporto em Paris e confuso sobre reservar um VTC, pegar um táxi ou usar Uber?
Neste guia completo, compararemos as três principais opções de transporte em Paris para ajudá-lo a tomar a melhor decisão.
</p>
<h2>O que é VTC?</h2>
<p>
VTC significa "Voiture de Transport avec Chauffeur" (Veículo de Transporte com Motorista). É um serviço
de motorista privado licenciado na França, similar aos serviços executivos de carros.
</p>
<h3>Características do VTC:</h3>
<ul>
<li>Serviço pré-reservado com preços fixos garantidos</li>
<li>Motoristas profissionais licenciados</li>
<li>Veículos premium (Mercedes, BMW)</li>
<li>Serviço de recepção no aeroporto com placa</li>
<li>Monitoramento de voo incluído sem custo extra</li>
<li>Sem preços dinâmicos ou surpresas</li>
</ul>
getExcursionFaqItems function · typescript · L158-L163 (6 LOC)src/data/excursions/faq-content.ts
export function getExcursionFaqItems(
language: Language,
destination: string,
): ExcursionFaqItem[] {
return faqBuilders[language](destination);
}useExitIntent function · typescript · L18-L148 (131 LOC)src/hooks/useExitIntent.ts
export default function useExitIntent({
sensitivity = 10,
delayMobile = 30000,
scrollThreshold = 0.5,
cookieExpiry = 24 * 60 * 60 * 1000, // 24 hours
onTrigger
}: ExitIntentConfig) {
const location = useLocation()
const [hasTriggered, setHasTriggered] = useState(false)
const [hasScrolled, setHasScrolled] = useState(false)
const [hasInteracted, setHasInteracted] = useState(false)
const timerRef = useRef<NodeJS.Timeout>()
// Routes where popup should NOT show
const excludedRoutes = ['/booking', '/payment', '/confirmation']
const isExcluded = excludedRoutes.some(route =>
location.pathname.startsWith(route)
)
// Check localStorage for previous popup display
const checkStorage = (): boolean => {
try {
const stored = localStorage.getItem('exitIntentShown')
if (!stored) return false
const data: StoredData = JSON.parse(stored)
const isExpired = Date.now() - data.timestamp > cookieExpiry
if (isExpired) {
localStouseLocationDetails function · typescript · L13-L35 (23 LOC)src/hooks/useLocationDetails.ts
export function useLocationDetails({ pickupId, dropoffId }: UseLocationDetailsProps) {
const [locationDetails, setLocationDetails] = useState<LocationDetails | null>(null);
useEffect(() => {
if (!pickupId || !dropoffId) return;
// Formatear los IDs para que sean más legibles
const formatLocationId = (id: string) => {
// Si es un UUID, mostrar solo los primeros 8 caracteres
if (id.includes('-')) {
return `Ubicación ${id.split('-')[0]}`;
}
return `Ubicación ${id.slice(0, 8)}`;
};
setLocationDetails({
pickup: formatLocationId(pickupId),
dropoff: formatLocationId(dropoffId)
});
}, [pickupId, dropoffId]);
return { locationDetails };
}Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
useIsMobile function · typescript · L5-L19 (15 LOC)src/hooks/use-mobile.tsx
export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
}
mql.addEventListener("change", onChange)
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
return () => mql.removeEventListener("change", onChange)
}, [])
return !!isMobile
}useScrollReveal function · typescript · L20-L61 (42 LOC)src/hooks/useScrollReveal.ts
export function useScrollReveal<T extends HTMLElement = HTMLDivElement>(
options: UseScrollRevealOptions = {}
) {
const {
threshold = 0.1,
rootMargin = '0px',
triggerOnce = true,
} = options;
const ref = useRef<T>(null);
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const element = ref.current;
if (!element) return;
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
if (triggerOnce) {
observer.unobserve(element);
}
} else if (!triggerOnce) {
setIsVisible(false);
}
},
{
threshold,
rootMargin,
}
);
observer.observe(element);
return () => {
observer.disconnect();
};
}, [threshold, rootMargin, triggerOnce]);
return { ref, isVisible };
}useStaggeredReveal function · typescript · L75-L89 (15 LOC)src/hooks/useScrollReveal.ts
export function useStaggeredReveal(
count: number,
options: UseScrollRevealOptions & { delay?: number } = {}
) {
const { delay = 100, ...revealOptions } = options;
const items = Array.from({ length: count }, () => useScrollReveal(revealOptions));
return items.map((item, index) => ({
...item,
style: {
animationDelay: `${index * delay}ms`,
animationFillMode: 'both' as const,
},
}));
}useServiceLevels function · typescript · L14-L59 (46 LOC)src/hooks/useServiceLevels.ts
export function useServiceLevels() {
const [serviceLevels, setServiceLevels] = useState<ServiceLevel[]>([]);
const [isLoading, setIsLoading] = useState(true);
const { toast } = useToast();
const { t } = useLanguage();
useEffect(() => {
const fetchServiceLevels = async () => {
try {
setIsLoading(true);
// TODO: Create service_levels table in Supabase
// For now, use vehicles table as fallback
const { data, error } = await supabase
.from('vehicles')
.select('*')
.order('base_price');
if (error) throw error;
// Map vehicles to service levels format
const mappedData = (data || []).map(vehicle => ({
id: vehicle.id,
name: vehicle.name,
description: { en: vehicle.description || '' },
features: vehicle.features || {},
multiplier: 1.0 // Default multiplier
}));
setServiceLevels(mappedData);
} catch (error) {
toast function · typescript · L13-L19 (7 LOC)src/hooks/use-toast.ts
export function toast(props: ToastProps) {
sonnerToast(props.title, {
description: props.description,
duration: props.duration || 5000,
action: props.action,
})
}useToast function · typescript · L21-L27 (7 LOC)src/hooks/use-toast.ts
export function useToast() {
return {
toast,
dismiss: sonnerToast.dismiss,
toasts: [] as any[]
}
}calculateReadingTime function · typescript · L8-L13 (6 LOC)src/lib/blog-utils.ts
export function calculateReadingTime(content: string): number {
const wordsPerMinute = 200;
const wordCount = content.trim().split(/\s+/).length;
const readingTime = Math.ceil(wordCount / wordsPerMinute);
return readingTime;
}generateTableOfContents function · typescript · L18-L41 (24 LOC)src/lib/blog-utils.ts
export function generateTableOfContents(
content: string,
): TableOfContentsItem[] {
const headingRegex = /^(#{2,3})\s+(.+)$/gm;
const headings: TableOfContentsItem[] = [];
let match;
while ((match = headingRegex.exec(content)) !== null) {
const level = match[1].length; // Number of # characters
const title = match[2].trim();
const id = title
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/(^-|-$)/g, "");
headings.push({
id,
title,
level,
});
}
return headings;
}All rows above produced by Repobility · https://repobility.com
formatDate function · typescript · L46-L54 (9 LOC)src/lib/blog-utils.ts
export function formatDate(dateString: string, locale: string = "en"): string {
const options: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "long",
day: "numeric",
};
return formatParisDateWithLocale(dateString, locale, options);
}getRelativeTime function · typescript · L59-L87 (29 LOC)src/lib/blog-utils.ts
export function getRelativeTime(
dateString: string,
locale: string = "en",
): string {
const date = new Date(dateString);
const now = new Date();
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
const intervals = {
year: 31536000,
month: 2592000,
week: 604800,
day: 86400,
hour: 3600,
minute: 60,
};
for (const [unit, seconds] of Object.entries(intervals)) {
const interval = Math.floor(diffInSeconds / seconds);
if (interval >= 1) {
return new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(
-interval,
unit as Intl.RelativeTimeFormatUnit,
);
}
}
return "just now";
}extractFirstParagraph function · typescript · L100-L110 (11 LOC)src/lib/blog-utils.ts
export function extractFirstParagraph(content: string): string {
// Remove headings
const withoutHeadings = content.replace(/^#{1,6}\s+.+$/gm, "");
// Get first non-empty paragraph
const paragraphs = withoutHeadings
.split("\n\n")
.filter((p) => p.trim().length > 0);
return paragraphs[0]?.trim() || "";
}generateSlug function · typescript · L115-L120 (6 LOC)src/lib/blog-utils.ts
export function generateSlug(title: string): string {
return title
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/(^-|-$)/g, "");
}getReadTimeText function · typescript · L125-L137 (13 LOC)src/lib/blog-utils.ts
export function getReadTimeText(
minutes: number,
locale: string = "en",
): string {
const texts = {
en: `${minutes} min read`,
fr: `${minutes} min de lecture`,
es: `${minutes} min de lectura`,
pt: `${minutes} min de leitura`,
};
return texts[locale as keyof typeof texts] || texts.en;
}parseMarkdownToHTML function · typescript · L143-L165 (23 LOC)src/lib/blog-utils.ts
export function parseMarkdownToHTML(markdown: string): string {
let html = markdown;
// Headers
html = html.replace(/^### (.*$)/gim, "<h3>$1</h3>");
html = html.replace(/^## (.*$)/gim, "<h2>$1</h2>");
html = html.replace(/^# (.*$)/gim, "<h1>$1</h1>");
// Bold
html = html.replace(/\*\*(.*?)\*\*/gim, "<strong>$1</strong>");
// Italic
html = html.replace(/\*(.*?)\*/gim, "<em>$1</em>");
// Links
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/gim, '<a href="$2">$1</a>');
// Line breaks
html = html.replace(/\n\n/g, "</p><p>");
html = "<p>" + html + "</p>";
return html;
}toDate function · typescript · L11-L16 (6 LOC)src/lib/datetime/paris.ts
function toDate(input: string | number | Date): Date {
if (input instanceof Date) {
return input;
}
return new Date(input);
}formatParisDateTime function · typescript · L22-L33 (12 LOC)src/lib/datetime/paris.ts
export function formatParisDateTime(
input: string | number | Date,
options?: Intl.DateTimeFormatOptions,
): string {
const date = toDate(input);
const mergedOptions: Intl.DateTimeFormatOptions = {
...options,
timeZone: PARIS_TZ,
};
return date.toLocaleString(undefined, mergedOptions);
}Repobility · severity-and-effort ranking · https://repobility.com
formatParisDate function · typescript · L39-L50 (12 LOC)src/lib/datetime/paris.ts
export function formatParisDate(
input: string | number | Date,
options?: Intl.DateTimeFormatOptions,
): string {
const date = toDate(input);
const mergedOptions: Intl.DateTimeFormatOptions = {
...options,
timeZone: PARIS_TZ,
};
return date.toLocaleDateString(undefined, mergedOptions);
}formatParisDateWithLocale function · typescript · L56-L68 (13 LOC)src/lib/datetime/paris.ts
export function formatParisDateWithLocale(
input: string | number | Date,
locale: string,
options?: Intl.DateTimeFormatOptions,
): string {
const date = toDate(input);
const mergedOptions: Intl.DateTimeFormatOptions = {
...options,
timeZone: PARIS_TZ,
};
return date.toLocaleDateString(locale, mergedOptions);
}buildEventWhatsAppUrl function · typescript · L63-L90 (28 LOC)src/lib/eventsPrefill.ts
export function buildEventWhatsAppUrl(
event: Event,
language: Language,
formatDate: (dateString: string) => string,
): string {
const t = getTemplates(language);
const lines: string[] = [];
lines.push(`${t.greeting}: ${event.title[language]}`);
if (event.startAt) {
lines.push(`${t.dateLabel}: ${formatDate(event.startAt)}`);
}
if (event.venueName?.[language]) {
lines.push(
`${t.venueLabel}: ${event.venueName[language]}${event.district ? ` (${event.district})` : ""}`,
);
}
if (event.eventUrl) {
lines.push(`${t.linkLabel}: ${event.eventUrl}`);
}
lines.push("");
lines.push(t.closing);
const text = encodeURIComponent(lines.join("\n"));
return `https://wa.me/${WHATSAPP_NUMBER}?text=${text}`;
}buildEventEmailUrl function · typescript · L92-L119 (28 LOC)src/lib/eventsPrefill.ts
export function buildEventEmailUrl(
event: Event,
language: Language,
formatDate: (dateString: string) => string,
): string {
const t = getTemplates(language);
const subject = encodeURIComponent(
`${t.genericSubject}: ${event.title[language]}`,
);
const bodyLines: string[] = [];
bodyLines.push(`${t.greeting}: ${event.title[language]}`);
if (event.startAt) {
bodyLines.push(`${t.dateLabel}: ${formatDate(event.startAt)}`);
}
if (event.venueName?.[language]) {
bodyLines.push(`${t.venueLabel}: ${event.venueName[language]}`);
}
if (event.eventUrl) {
bodyLines.push(`${t.linkLabel}: ${event.eventUrl}`);
}
bodyLines.push("");
bodyLines.push(t.closing);
const body = encodeURIComponent(bodyLines.join("\n"));
return `mailto:${EMAIL_ADDRESS}?subject=${subject}&body=${body}`;
}buildGenericEmailUrl function · typescript · L127-L132 (6 LOC)src/lib/eventsPrefill.ts
export function buildGenericEmailUrl(language: string): string {
const t = getTemplates(language);
const subject = encodeURIComponent(t.genericSubject);
const body = encodeURIComponent(t.genericBody);
return `mailto:${EMAIL_ADDRESS}?subject=${subject}&body=${body}`;
}generateArticleJsonLd function · typescript · L64-L104 (41 LOC)src/lib/seo/json-ld.ts
export function generateArticleJsonLd(
post: BlogPostMeta,
lang: Language,
url: string,
): JsonLdArticle {
const category = getCategoryBySlug(post.category);
// Handle keywords - BlogPostMeta.seo.keywords is always string[]
const keywords: string = post.seo.keywords
? post.seo.keywords.join(", ")
: "";
return {
"@context": "https://schema.org",
"@type": "Article",
headline: post.title[lang],
description: post.description[lang],
image: post.image.url,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
author: {
"@type": "Person",
name: post.author.name,
},
publisher: {
"@type": "Organization",
name: "Paris Luxe Journey",
logo: {
"@type": "ImageObject",
url: "https://parisluxejourney.com/logo.png",
},
},
mainEntityOfPage: {
"@type": "WebPage",
"@id": url,
},
articleSection: category?.name[lang],
keywords,
inLanguage: lang,
}generateBreadcrumbJsonLd function · typescript · L109-L122 (14 LOC)src/lib/seo/json-ld.ts
export function generateBreadcrumbJsonLd(
items: Array<{ name: string; url?: string }>,
): JsonLdBreadcrumb {
return {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: items.map((item, index) => ({
"@type": "ListItem",
position: index + 1,
name: item.name,
...(item.url && { item: item.url }),
})),
};
}generateWebsiteJsonLd function · typescript · L127-L144 (18 LOC)src/lib/seo/json-ld.ts
export function generateWebsiteJsonLd(): JsonLdWebsite {
return {
"@context": "https://schema.org",
"@type": "WebSite",
name: "Paris Luxe Journey",
url: "https://parisluxejourney.com",
description: "Premium airport transfer and travel services in Paris",
potentialAction: {
"@type": "SearchAction",
target: {
"@type": "EntryPoint",
urlTemplate:
"https://parisluxejourney.com/blog?search={search_term_string}",
},
"query-input": "required name=search_term_string",
},
};
}Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
generateOrganizationJsonLd function · typescript · L182-L198 (17 LOC)src/lib/seo/json-ld.ts
export function generateOrganizationJsonLd(params: {
name: string;
url: string;
logoUrl?: string;
sameAs?: string[];
description?: string;
}): JsonLdOrganization {
return {
"@context": "https://schema.org",
"@type": "Organization",
name: params.name,
url: params.url,
...(params.logoUrl && { logo: params.logoUrl }),
...(params.sameAs && { sameAs: params.sameAs }),
...(params.description && { description: params.description }),
};
}generateLocalBusinessJsonLd function · typescript · L203-L242 (40 LOC)src/lib/seo/json-ld.ts
export function generateLocalBusinessJsonLd(params: {
name: string;
url: string;
telephone?: string;
address?: {
streetAddress?: string;
addressLocality?: string;
addressRegion?: string;
postalCode?: string;
addressCountry?: string;
};
geo?: {
latitude?: string;
longitude?: string;
};
priceRange?: string;
description?: string;
}): JsonLdLocalBusiness {
return {
"@context": "https://schema.org",
"@type": "LocalBusiness",
name: params.name,
url: params.url,
...(params.telephone && { telephone: params.telephone }),
...(params.address && {
address: {
"@type": "PostalAddress",
...params.address,
},
}),
...(params.geo && {
geo: {
"@type": "GeoCoordinates",
...params.geo,
},
}),
...(params.priceRange && { priceRange: params.priceRange }),
...(params.description && { description: params.description }),
};
}getSiteOrigin function · typescript · L6-L26 (21 LOC)src/lib/seo/site.ts
export function getSiteOrigin(): string {
// Runtime: use actual domain (supports eliteparistransfer.com, parisluxejourney.com, etc.)
if (typeof window !== "undefined" && window.location?.origin) {
return window.location.origin;
}
// Build/SSR fallback
const envUrl = (
import.meta.env?.VITE_PUBLIC_SITE_URL as string | undefined
)?.trim();
if (envUrl) {
try {
return new URL(envUrl).origin;
} catch {
return envUrl.replace(/\/+$/, "");
}
}
return "https://eliteparistransfer.com";
}AgenciesPage function · typescript · L7-L69 (63 LOC)src/pages/Agencies.tsx
export default function AgenciesPage() {
const { t } = useLanguage();
const bullets = [
t.agencies.bullets.volume,
t.agencies.bullets.invoicing,
t.agencies.bullets.support,
t.agencies.bullets.availability,
];
return (
<>
<Helmet>
<title>{t.agencies.metaTitle}</title>
<meta name="description" content={t.agencies.intro} />
</Helmet>
<section className="py-16 md:py-20 bg-background">
<div className="container mx-auto px-4 max-w-4xl">
<div className="rounded-2xl border border-border bg-card p-6 md:p-10 shadow-sm">
<h1 className="text-3xl md:text-4xl font-display font-bold text-secondary mb-4">
{t.agencies.h1}
</h1>
<p className="text-base md:text-lg text-muted-foreground mb-6 leading-relaxed">
{t.agencies.intro}
</p>
<ul className="space-y-3 mb-6">
{bullets.map((bullet) => (
<li key={bullet}BlogCategory function · typescript · L16-L168 (153 LOC)src/pages/blog/BlogCategory.tsx
export default function BlogCategory() {
const { category } = useParams<{ category: string }>();
const navigate = useNavigate();
const { i18n, t } = useTranslation();
const currentLang = i18n.language as "en" | "es" | "fr" | "pt";
const [searchQuery, setSearchQuery] = useState("");
// Validate category
if (!category || !isValidCategory(category)) {
navigate("/blog/404", { replace: true });
return null;
}
const categoryMeta = getCategoryBySlug(category)!;
const allPosts = getPostsByCategory(category);
// Filter posts by search query
const filteredPosts = allPosts.filter((post) => {
if (searchQuery === "") return true;
const query = searchQuery.toLowerCase();
return (
post.title[currentLang].toLowerCase().includes(query) ||
post.description[currentLang].toLowerCase().includes(query) ||
post.tags.some((tag) => tag.toLowerCase().includes(query))
);
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
loadPost function · typescript · L40-L91 (52 LOC)src/pages/blog/BlogPost.tsx
async function loadPost() {
if (!category || !slug) {
setError(true);
setLoading(false);
return;
}
// Validate category
if (!isValidCategory(category)) {
navigate("/blog/404", { replace: true });
return;
}
// Get post metadata
const postMeta = getPostBySlug(slug);
if (!postMeta) {
navigate("/blog/404", { replace: true });
return;
}
// Verify category matches
if (postMeta.category !== category) {
navigate(`/blog/${postMeta.category}/${slug}`, { replace: true });
return;
}
setPost(postMeta);
// Load article content
try {
const exists = await articleExists(slug, currentLang);
if (!exists) {
// Fallback to English if translation doesn't exist
const existsEn = await articleExists(slug, "en");
if (!existsEn) {
setError(true);
setLoading(false);
BlogNotFound function · typescript · L9-L107 (99 LOC)src/pages/blog/NotFound.tsx
export default function BlogNotFound() {
const { t } = useTranslation()
// Get 3 random popular posts to suggest
const suggestedPosts = blogPosts
.sort(() => Math.random() - 0.5)
.slice(0, 3)
return (
<>
<Helmet>
<title>{t('blog.notFound.title') || '404 - Page Not Found | Blog'}</title>
<meta name="robots" content="noindex, nofollow" />
</Helmet>
<div className="min-h-screen bg-background">
{/* 404 Hero */}
<section className="relative bg-gradient-to-br from-primary/10 via-background to-background py-20 md:py-32">
<div className="container mx-auto px-4">
<div className="max-w-3xl mx-auto text-center">
{/* 404 Number */}
<div className="text-9xl md:text-[12rem] font-bold text-primary/20 leading-none mb-4">
404
</div>
{/* Title */}
<h1 className="text-4xl md:text-5xl font-bold text-foreground mb-6">
BookingPage function · typescript · L22-L84 (63 LOC)src/pages/booking/BookingPage.tsx
export default function BookingPage() {
const navigate = useNavigate();
const { t } = useLanguage();
const { toast } = useToast();
const [currentStep, setCurrentStep] = React.useState<'details' | 'payment' | 'confirmation'>('details');
const [bookingDetails, setBookingDetails] = React.useState<BookingDetails>({
tourId: 'default-tour',
tourName: 'Default Tour'
// Eliminamos basePrice del estado inicial
});
const [selectedTour, setSelectedTour] = React.useState<any>(null);
const [isProcessing, setIsProcessing] = React.useState(false);
const [error, setError] = React.useState('');
const handleBookingSubmit = async (details: BookingDetails) => {
try {
setBookingDetails(details);
setCurrentStep('payment');
} catch (err) {
setError(err instanceof Error ? err.message : 'Error al procesar la reserva');
}
};
const handlePaymentSuccess = async (paymentDetails: PaymentDetails) => {
try {
setIsProcessing(true);
// Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
formatParisDateTime function · typescript · L53-L64 (12 LOC)src/pages/booking/Confirmation.tsx
function formatParisDateTime(value: string | null | undefined): string | null {
if (!value) {
return null;
}
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return null;
}
return PARIS_DATE_TIME_FORMATTER.format(date);
}CompaniesPage function · typescript · L7-L69 (63 LOC)src/pages/Companies.tsx
export default function CompaniesPage() {
const { t } = useLanguage();
const bullets = [
t.companies.bullets.billing,
t.companies.bullets.routes,
t.companies.bullets.chauffeurs,
t.companies.bullets.support,
];
return (
<>
<Helmet>
<title>{t.companies.metaTitle}</title>
<meta name="description" content={t.companies.intro} />
</Helmet>
<section className="py-16 md:py-20 bg-background">
<div className="container mx-auto px-4 max-w-4xl">
<div className="rounded-2xl border border-border bg-card p-6 md:p-10 shadow-sm">
<h1 className="text-3xl md:text-4xl font-display font-bold text-secondary mb-4">
{t.companies.h1}
</h1>
<p className="text-base md:text-lg text-muted-foreground mb-6 leading-relaxed">
{t.companies.intro}
</p>
<ul className="space-y-3 mb-6">
{bullets.map((bullet) => (
<li key={buDesignPreview function · typescript · L5-L188 (184 LOC)src/pages/DesignPreview.tsx
export default function DesignPreview() {
const [passengersBefore, setPassengersBefore] = useState(2);
const [passengersAfter, setPassengersAfter] = useState(2);
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 p-8">
<div className="max-w-7xl mx-auto">
<h1 className="text-4xl font-display text-primary mb-2 text-center">
🎨 Design Preview - Paris Elite Services
</h1>
<p className="text-center text-slate-600 mb-12">
Comparación lado a lado: Antes vs. Después
</p>
{/* 1. HERO OVERLAY */}
<section className="mb-16">
<h2 className="text-2xl font-display text-primary mb-6">1. Hero Overlay</h2>
<div className="grid md:grid-cols-2 gap-8">
{/* ANTES */}
<div>
<p className="text-sm font-semibold text-red-600 mb-3">❌ ANTES (Plano)</p>
<div className="relative h-64 rounded-xl overflow-hidden">
DestinationPage function · typescript · L9-L77 (69 LOC)src/pages/destination/[id].tsx
export default function DestinationPage() {
const { id } = useParams();
const [activeSection, setActiveSection] = React.useState('description');
const navigationItems = [
{ id: 'description', label: 'Description' },
{ id: 'tours', label: 'Tours' },
{ id: 'map', label: 'Map' },
{ id: 'events', label: 'Events' },
{ id: 'faq', label: 'FAQ' }
];
const destinationData = {
title: 'Destination Title',
image: '/images/destination.jpg',
distance: '30km from Paris',
duration: '1 day',
currentPath: `/destination/${id}`
};
const tours = [
{
id: '1',
title: 'Tour Name',
description: 'Tour Description',
duration: '4 hours',
price: 99,
includes: ['Item 1', 'Item 2']
}
];
const renderTours = () => (
<div className="grid gap-6">
{tours.map(tour => (
<TourCard
key={tour.id}
title={tour.title}
description={tour.description}
duration={tour.duChampagnePage function · typescript · L11-L133 (123 LOC)src/pages/excursions/champagne.tsx
export default function ChampagnePage() {
const { t, language } = useLanguage();
const [activeSection, setActiveSection] = React.useState("description");
const [selectedTour, setSelectedTour] = React.useState<string | null>(null);
const champagneData = t.champagne;
const excursionData = excursions.find((e) => e.id === "champagne");
const navigationItems = [
{ id: "description", label: t.champagne.navigation.description },
{ id: "tours", label: t.champagne.navigation.tours },
{ id: "map", label: t.champagne.navigation.map },
{ id: "events", label: t.champagne.navigation.events },
{ id: "faq", label: t.champagne.navigation.faq },
];
const handleSectionChange = (sectionId: string) => {
setActiveSection(sectionId);
};
const faqItems = getExcursionFaqItems(language, t.champagne.title);
const content = {
description: (
<div>
<h3 className="text-2xl font-bold mb-4">{champagneData.title}</h3>
<p className="mb-4">{chamGivernyHonfleurPage function · typescript · L11-L129 (119 LOC)src/pages/excursions/giverny-honfleur.tsx
export default function GivernyHonfleurPage() {
const { t, language } = useLanguage();
const [activeSection, setActiveSection] = React.useState("description");
const [selectedTour, setSelectedTour] = React.useState<string | null>(null);
const givernyData = t.giverny;
const excursionData = excursions.find((e) => e.id === "giverny-honfleur");
const navigationItems = [
{ id: "description", label: t.giverny.navigation.description },
{ id: "tours", label: t.giverny.navigation.tours },
{ id: "map", label: t.giverny.navigation.map },
{ id: "events", label: t.giverny.navigation.events },
{ id: "faq", label: t.giverny.navigation.faq },
];
const handleSectionChange = (sectionId: string) => {
setActiveSection(sectionId);
};
const faqItems = getExcursionFaqItems(language, t.giverny.title);
const content = {
description: (
<div>
<h3 className="text-2xl font-bold mb-4">{givernyData.title}</h3>
<p className="mb-4">{givernyDaExcursionsPage function · typescript · L26-L94 (69 LOC)src/pages/excursions/index.tsx
export default function ExcursionsPage() {
const { t } = useTranslation();
const [searchQuery, setSearchQuery] = useState("");
const [selectedDuration, setSelectedDuration] = useState("");
const [selectedType, setSelectedType] = useState("");
return (
<div className="min-h-screen bg-background">
<main className="container mx-auto px-4 py-8">
<div className="space-y-8">
{/* Filtros */}
<div className="flex flex-col md:flex-row gap-4">
<Input
type="text"
placeholder={t('excursions.search.placeholder')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="md:w-1/3"
/>
<Select
value={selectedDuration}
onValueChange={setSelectedDuration}
>
<SelectTrigger className="md:w-1/4">
<SelectValue placeholder={t('excursions.search.durationLoireValleyPage function · typescript · L11-L125 (115 LOC)src/pages/excursions/loire-valley.tsx
export default function LoireValleyPage() {
const { t, language } = useLanguage();
const [activeSection, setActiveSection] = React.useState("description");
const [selectedTour, setSelectedTour] = React.useState<string | null>(null);
const loireData = t.loire;
const excursionData = excursions.find((e) => e.id === "loire-valley");
const navigationItems = [
{ id: "description", label: t.loire.navigation.description },
{ id: "tours", label: t.loire.navigation.tours },
{ id: "map", label: t.loire.navigation.map },
{ id: "events", label: t.loire.navigation.events },
{ id: "faq", label: t.loire.navigation.faq },
];
const handleSectionChange = (sectionId: string) => {
setActiveSection(sectionId);
};
const faqItems = getExcursionFaqItems(language, t.loire.title);
const content = {
description: (
<div>
<h3 className="text-2xl font-bold mb-4">{loireData.title}</h3>
<p className="mb-4">{loireData.description}</p>
All rows above produced by Repobility · https://repobility.com
VersaillesPage function · typescript · L11-L154 (144 LOC)src/pages/excursions/versailles.tsx
export default function VersaillesPage() {
const { t, language } = useLanguage();
const [activeSection, setActiveSection] = React.useState("description");
const [selectedTour, setSelectedTour] = React.useState<string | null>(null);
// Get versailles data from translations
const versaillesData = t.versailles;
// Navigation items
const navigationItems = [
{ id: "description", label: t.versailles.navigation.description },
{ id: "tours", label: t.versailles.navigation.tours },
{ id: "map", label: t.versailles.navigation.map },
{ id: "events", label: t.versailles.navigation.events },
{ id: "faq", label: t.versailles.navigation.faq },
];
// Handle section change
const handleSectionChange = (sectionId: string) => {
setActiveSection(sectionId);
};
const faqItems = getExcursionFaqItems(language, t.versailles.title);
// Enhanced tours data with more details
const tours = [
{
id: "versailles-tour-1",
name: "Guided Tour of VeFAQPage function · typescript · L5-L64 (60 LOC)src/pages/FAQPage.tsx
export default function FAQPage() {
const { t } = useLanguage();
return (
<div className="min-h-screen bg-gradient-to-b from-white via-champagne/30 to-white">
{/* Hero Section */}
<section className="relative py-20 bg-gradient-to-br from-primary/10 via-champagne/20 to-white">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-4xl">
<div className="text-center">
<h1 className="text-4xl md:text-5xl lg:text-6xl font-display font-bold text-secondary mb-6">
{t.faq?.title || "Frequently Asked Questions"}
</h1>
<p className="text-lg md:text-xl text-gray-600 max-w-2xl mx-auto leading-relaxed">
{t.faq?.subtitle || "Find answers to common questions about our premium transfer services"}
</p>
</div>
</div>
</section>
{/* FAQ Component */}
<section className="py-12">
<FAQ />
</section>
{/* CTA Section */}
<sectioHome function · typescript · L19-L171 (153 LOC)src/pages/Home.tsx
export default function Home() {
const { t, language } = useLanguage();
// Use runtime domain (supports eliteparistransfer.com, parisluxejourney.com, etc.)
const siteOrigin = getSiteOrigin();
// Generate JSON-LD structured data
const organizationJsonLd = generateOrganizationJsonLd({
name: "Paris Luxe Journey",
url: siteOrigin,
logoUrl: `${siteOrigin}/logo.png`,
description: t.seo.home.description,
sameAs: [
"https://www.facebook.com/parisluxejourney",
"https://www.instagram.com/parisluxejourney",
],
});
const localBusinessJsonLd = generateLocalBusinessJsonLd({
name: "Paris Luxe Journey",
url: siteOrigin,
telephone: "+33668251102",
description: t.seo.home.description,
priceRange: "€€€",
address: {
addressLocality: "Paris",
addressRegion: "Île-de-France",
addressCountry: "FR",
},
});
const canonicalUrl = `${siteOrigin}/${language}`;
const handleCtaClickCapture = (event: React.MouseE