From 823c722f94339032e7a720dd5ee478f792afbb78 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 20:02:27 +0000 Subject: [PATCH 1/4] Initial plan From 39f6fd22830a04757a3cdf592394ac5cc59fd77f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 20:12:30 +0000 Subject: [PATCH 2/4] Refactor date formatting and data normalization utilities - Create reusable date formatting utilities in lib/i18n.ts - Create data normalization utilities in lib/utils.ts - Update Blog.tsx, Projects.tsx, Dashboard.tsx, blog/[slug].tsx, and CommentsSection.tsx to use new date formatting utilities - Update Contact.tsx and About.tsx to use new normalization utilities - Reduce code duplication across 7 files Co-authored-by: marcelo-m7 <117441129+marcelo-m7@users.noreply.github.com> --- src/components/blog/CommentsSection.tsx | 24 ++---- src/lib/i18n.ts | 49 +++++++++++ src/lib/utils.ts | 107 ++++++++++++++++++++++++ src/pages/About.tsx | 62 ++++---------- src/pages/Blog.tsx | 19 +---- src/pages/Contact.tsx | 54 +----------- src/pages/Dashboard.tsx | 51 +++-------- src/pages/Projects.tsx | 48 +++-------- src/pages/blog/[slug].tsx | 17 +--- 9 files changed, 209 insertions(+), 222 deletions(-) diff --git a/src/components/blog/CommentsSection.tsx b/src/components/blog/CommentsSection.tsx index bd3aafe..d0e43de 100644 --- a/src/components/blog/CommentsSection.tsx +++ b/src/components/blog/CommentsSection.tsx @@ -11,7 +11,7 @@ import { Textarea } from '@/components/ui/textarea'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Loader2 } from 'lucide-react'; import { Link } from 'react-router-dom'; -import { getNormalizedLocale } from '@/lib/i18n'; +import { createDateFormatter } from '@/lib/i18n'; interface CommentsSectionProps { postId: string; @@ -47,26 +47,14 @@ const CommentsSection = ({ postId }: CommentsSectionProps) => { const queryClient = useQueryClient(); const [newComment, setNewComment] = useState(''); - const normalizedLocale = useMemo( - () => getNormalizedLocale(i18n.language), + const dateFormatter = useMemo( + () => createDateFormatter(i18n.language, { + dateStyle: 'medium', + timeStyle: 'short', + }), [i18n.language] ); - const dateFormatter = useMemo(() => { - try { - return new Intl.DateTimeFormat(normalizedLocale, { - dateStyle: 'medium', - timeStyle: 'short', - }); - } catch (error) { - console.error('Unsupported locale for comment date formatting', error); - return new Intl.DateTimeFormat('en-US', { - dateStyle: 'medium', - timeStyle: 'short', - }); - } - }, [normalizedLocale]); - const { data: comments, isLoading, diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts index b4013a5..d2668a6 100644 --- a/src/lib/i18n.ts +++ b/src/lib/i18n.ts @@ -20,3 +20,52 @@ export const getNormalizedLocale = (language: string | undefined | null) => { return language; } }; + +/** + * Creates a date formatter with fallback handling + * @param locale - The locale to use for formatting + * @param options - Intl.DateTimeFormat options + * @returns A DateTimeFormat instance with fallback to en-US on error + */ +export const createDateFormatter = ( + locale: string | undefined | null, + options: Intl.DateTimeFormatOptions = { dateStyle: 'medium' } +): Intl.DateTimeFormat => { + const normalizedLocale = getNormalizedLocale(locale); + + try { + return new Intl.DateTimeFormat(normalizedLocale, options); + } catch (error) { + console.error(`Unsupported locale for date formatting: ${normalizedLocale}`, error); + return new Intl.DateTimeFormat('en-US', options); + } +}; + +/** + * Formats a date string with fallback handling + * @param dateString - The date string to format + * @param formatter - The DateTimeFormat instance to use + * @param fallbackFormatter - Optional fallback formatter + * @returns Formatted date string or em-dash if invalid + */ +export const formatDate = ( + dateString: string | null | undefined, + formatter: Intl.DateTimeFormat, + fallbackFormatter?: Intl.DateTimeFormat +): string => { + if (!dateString) return '—'; + + try { + return formatter.format(new Date(dateString)); + } catch (error) { + console.error('Error formatting date', error); + if (fallbackFormatter) { + try { + return fallbackFormatter.format(new Date(dateString)); + } catch { + return '—'; + } + } + return '—'; + } +}; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 2819a83..75d7cde 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -4,3 +4,110 @@ import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } + +/** + * Type guard to check if value is a non-empty string + */ +const isNonEmptyString = (value: unknown): value is string => + typeof value === 'string' && value.trim().length > 0; + +/** + * Normalizes a value to an array of strings + * Handles JSON strings, arrays, and objects with an 'options' property + * @param value - The value to normalize + * @returns An array of unique non-empty strings + */ +export const normalizeToStringArray = (value: unknown): string[] => { + if (value === null || value === undefined) { + return []; + } + + let parsedValue = value; + + // Try to parse JSON string + if (typeof parsedValue === 'string') { + const trimmedValue = parsedValue.trim(); + if (!trimmedValue) { + return []; + } + + try { + parsedValue = JSON.parse(trimmedValue); + } catch { + return [trimmedValue]; + } + } + + // Handle arrays + if (Array.isArray(parsedValue)) { + return Array.from( + new Set( + parsedValue + .filter(isNonEmptyString) + .map((item) => item.trim()) + ) + ); + } + + // Handle objects with 'options' or 'stats' property + if (typeof parsedValue === 'object' && parsedValue !== null) { + const record = parsedValue as Record; + if (Array.isArray(record.options)) { + return Array.from( + new Set( + record.options + .filter(isNonEmptyString) + .map((item) => item.trim()) + ) + ); + } + } + + return []; +}; + +/** + * Normalizes a value to an array of typed objects + * @param value - The value to normalize + * @param validator - Function to validate and transform each item + * @returns An array of validated objects + */ +export const normalizeToTypedArray = ( + value: unknown, + validator: (item: unknown) => T | null +): T[] => { + if (!value) { + return []; + } + + let parsedValue: unknown = value; + + // Try to parse JSON string + if (typeof parsedValue === 'string') { + try { + parsedValue = JSON.parse(parsedValue); + } catch { + return []; + } + } + + // Handle arrays + if (Array.isArray(parsedValue)) { + return parsedValue + .map(validator) + .filter((item): item is T => item !== null); + } + + // Handle objects with nested arrays + if (typeof parsedValue === 'object' && parsedValue !== null) { + const record = parsedValue as Record; + if (Array.isArray(record.stats)) { + return normalizeToTypedArray(record.stats, validator); + } + if (Array.isArray(record.options)) { + return normalizeToTypedArray(record.options, validator); + } + } + + return []; +}; diff --git a/src/pages/About.tsx b/src/pages/About.tsx index cf2725e..7aaca54 100644 --- a/src/pages/About.tsx +++ b/src/pages/About.tsx @@ -9,6 +9,7 @@ import { Button } from '@/components/ui/button'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { supabase } from '@/integrations/supabase'; import { useTranslation } from 'react-i18next'; +import { normalizeToTypedArray } from '@/lib/utils'; interface TeamMemberCard { id: string; @@ -22,51 +23,6 @@ interface AboutStat { label: string; } -const normalizeAboutStats = (value: unknown): AboutStat[] => { - if (!value) { - return []; - } - - let parsedValue: unknown = value; - - if (typeof parsedValue === 'string') { - try { - parsedValue = JSON.parse(parsedValue); - } catch { - return []; - } - } - - if (Array.isArray(parsedValue)) { - return parsedValue - .map((item) => { - if (item && typeof item === 'object') { - const record = item as Record; - const number = record.number; - const label = record.label; - - if ((typeof number === 'string' || typeof number === 'number') && typeof label === 'string') { - return { - number: number.toString(), - label, - } satisfies AboutStat; - } - } - return null; - }) - .filter((stat): stat is AboutStat => stat !== null); - } - - if (typeof parsedValue === 'object' && parsedValue !== null) { - const record = parsedValue as Record; - if (Array.isArray(record.stats)) { - return normalizeAboutStats(record.stats); - } - } - - return []; -}; - const About = () => { const { t } = useTranslation(); const values = useMemo( @@ -133,7 +89,21 @@ const About = () => { if (error) throw error; - return normalizeAboutStats(data?.value); + return normalizeToTypedArray(data?.value, (item) => { + if (item && typeof item === 'object') { + const record = item as Record; + const number = record.number; + const label = record.label; + + if ((typeof number === 'string' || typeof number === 'number') && typeof label === 'string') { + return { + number: number.toString(), + label, + }; + } + } + return null; + }); }, }); diff --git a/src/pages/Blog.tsx b/src/pages/Blog.tsx index c4fe407..6f4b957 100644 --- a/src/pages/Blog.tsx +++ b/src/pages/Blog.tsx @@ -31,7 +31,7 @@ import { PaginationEllipsis, } from '@/components/ui/pagination'; import { cn } from '@/lib/utils'; -import { getNormalizedLocale } from '@/lib/i18n'; +import { createDateFormatter } from '@/lib/i18n'; import type { Database } from '@/integrations/supabase/types'; const FALLBACK_IMAGE = @@ -94,24 +94,11 @@ const Blog = () => { const { t, i18n } = useTranslation(); const [page, setPage] = useState(1); - const normalizedLocale = useMemo( - () => getNormalizedLocale(i18n.language), + const dateFormatter = useMemo( + () => createDateFormatter(i18n.language, { dateStyle: 'medium' }), [i18n.language] ); - const dateFormatter = useMemo(() => { - try { - return new Intl.DateTimeFormat(normalizedLocale, { - dateStyle: 'medium', - }); - } catch (error) { - console.error('Unsupported locale for blog date formatting', error); - return new Intl.DateTimeFormat('en-US', { - dateStyle: 'medium', - }); - } - }, [normalizedLocale]); - const categories = useMemo( () => BLOG_CATEGORY_KEYS.map((key) => t(key)), [t] diff --git a/src/pages/Contact.tsx b/src/pages/Contact.tsx index 25274d9..d4bca40 100644 --- a/src/pages/Contact.tsx +++ b/src/pages/Contact.tsx @@ -19,6 +19,7 @@ import { BreadcrumbSeparator, } from '@/components/ui/breadcrumb'; import { useQuery } from '@tanstack/react-query'; +import { normalizeToStringArray } from '@/lib/utils'; const PROJECT_TYPE_KEYS = [ 'contact.projectTypes.customAssistant', @@ -37,57 +38,6 @@ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const isValidatableField = (value: string): value is ValidatableField => (validatableFields as readonly string[]).includes(value); -const isNonEmptyString = (value: unknown): value is string => - typeof value === 'string' && value.trim().length > 0; - -const normalizeProjectTypes = (value: unknown): string[] => { - if (value === null || value === undefined) { - return []; - } - - let parsedValue = value; - - if (typeof parsedValue === 'string') { - const trimmedValue = parsedValue.trim(); - - if (!trimmedValue) { - return []; - } - - try { - parsedValue = JSON.parse(trimmedValue); - } catch { - return [trimmedValue]; - } - } - - if (Array.isArray(parsedValue)) { - return Array.from( - new Set( - parsedValue - .filter(isNonEmptyString) - .map((option) => option.trim()) - ) - ); - } - - if (typeof parsedValue === 'object' && parsedValue !== null) { - const record = parsedValue as Record; - - if (Array.isArray(record.options)) { - return Array.from( - new Set( - record.options - .filter(isNonEmptyString) - .map((option) => option.trim()) - ) - ); - } - } - - return []; -}; - const Contact = () => { const { t } = useTranslation(); const [formData, setFormData] = useState({ @@ -121,7 +71,7 @@ const Contact = () => { if (error) throw error; - return normalizeProjectTypes(data?.value); + return normalizeToStringArray(data?.value); }, staleTime: 1000 * 60 * 10, }); diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index d9618bd..311b47c 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -26,7 +26,7 @@ import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import Loading from '@/components/Loading'; import { AlertTriangle, Loader2, LogOut, RefreshCcw } from 'lucide-react'; import { useTranslation } from 'react-i18next'; -import { getNormalizedLocale } from '@/lib/i18n'; +import { createDateFormatter, formatDate } from '@/lib/i18n'; type Profile = Database['public']['Tables']['profiles']['Row']; type Lead = Database['public']['Tables']['leads']['Row']; @@ -149,44 +149,17 @@ const Dashboard = () => { void loadDashboard(); }, [loadDashboard]); - const normalizedLocale = useMemo( - () => getNormalizedLocale(i18n.language), + const dateTimeFormatter = useMemo( + () => createDateFormatter(i18n.language, { + dateStyle: 'short', + timeStyle: 'short', + }), [i18n.language] ); - const fallbackDateFormatter = useMemo( - () => - new Intl.DateTimeFormat('en-US', { - dateStyle: 'short', - timeStyle: 'short', - }), - [] - ); - - const dateTimeFormatter = useMemo(() => { - try { - return new Intl.DateTimeFormat(normalizedLocale, { - dateStyle: 'short', - timeStyle: 'short', - }); - } catch (error) { - console.error('Unsupported locale for dashboard date formatting', error); - return fallbackDateFormatter; - } - }, [fallbackDateFormatter, normalizedLocale]); - - const formatDate = useCallback( - (value: string | null | undefined) => { - if (!value) return '—'; - - try { - return dateTimeFormatter.format(new Date(value)); - } catch (error) { - console.error('Error formatting dashboard date', error); - return fallbackDateFormatter.format(new Date(value)); - } - }, - [dateTimeFormatter, fallbackDateFormatter] + const formatDashboardDate = useCallback( + (value: string | null | undefined) => formatDate(value, dateTimeFormatter), + [dateTimeFormatter] ); const handleRefresh = () => { @@ -350,7 +323,7 @@ const Dashboard = () => { {t('dashboard.profile.updatedAt')}

- {formatDate(profile?.updated_at)} + {formatDashboardDate(profile?.updated_at)}

@@ -401,7 +374,7 @@ const Dashboard = () => { {lead.project ?? '—'} {lead.message} - {formatDate(lead.created_at)} + {formatDashboardDate(lead.created_at)} ))} @@ -451,7 +424,7 @@ const Dashboard = () => { - {formatDate(subscriber.subscribed_at)} + {formatDashboardDate(subscriber.subscribed_at)} ))} diff --git a/src/pages/Projects.tsx b/src/pages/Projects.tsx index c75d31f..503100c 100644 --- a/src/pages/Projects.tsx +++ b/src/pages/Projects.tsx @@ -25,7 +25,7 @@ import { } from '@/lib/solutions'; import type { GitHubRepository } from '@/lib/solutions'; import type { SolutionContent } from '@/types/solutions'; -import { getNormalizedLocale } from '@/lib/i18n'; +import { createDateFormatter, formatDate } from '@/lib/i18n'; import { SolutionCard, sectionContainer, @@ -52,44 +52,18 @@ const Projects = () => { const memoizedFallbackSolutions = useMemo(() => getFallbackSolutions(), []); - const normalizedLocale = useMemo( - () => getNormalizedLocale(i18n.language), + const dateFormatter = useMemo( + () => createDateFormatter(i18n.language, { + year: 'numeric', + month: 'short', + day: 'numeric', + }), [i18n.language] ); - const fallbackDateFormatter = useMemo( - () => - new Intl.DateTimeFormat('en-US', { - year: 'numeric', - month: 'short', - day: 'numeric', - }), - [] - ); - - const dateFormatter = useMemo(() => { - try { - return new Intl.DateTimeFormat(normalizedLocale, { - year: 'numeric', - month: 'short', - day: 'numeric', - }); - } catch (error) { - console.error('Unsupported locale for project date formatting', error); - return fallbackDateFormatter; - } - }, [fallbackDateFormatter, normalizedLocale]); - - const formatDate = useCallback( - (dateString: string) => { - try { - return dateFormatter.format(new Date(dateString)); - } catch (error) { - console.error('Error formatting project date', error); - return fallbackDateFormatter.format(new Date(dateString)); - } - }, - [dateFormatter, fallbackDateFormatter] + const formatProjectDate = useCallback( + (dateString: string) => formatDate(dateString, dateFormatter), + [dateFormatter] ); const { @@ -457,7 +431,7 @@ const Projects = () => {
- {formatDate(repo.created_at)} + {formatProjectDate(repo.created_at)}

diff --git a/src/pages/blog/[slug].tsx b/src/pages/blog/[slug].tsx index b1e024f..989b7b9 100644 --- a/src/pages/blog/[slug].tsx +++ b/src/pages/blog/[slug].tsx @@ -8,7 +8,7 @@ import Meta from '@/components/Meta'; import NewsletterSection from '@/components/NewsletterSection'; import CommentsSection from '@/components/blog/CommentsSection'; import { supabase } from '@/integrations/supabase'; -import { getNormalizedLocale } from '@/lib/i18n'; +import { createDateFormatter } from '@/lib/i18n'; import type { Database } from '@/integrations/supabase/types'; import { Breadcrumb, @@ -213,22 +213,11 @@ const BlogPostPage = () => { const { slug } = useParams<{ slug: string }>(); const { t, i18n } = useTranslation(); - const normalizedLocale = useMemo( - () => getNormalizedLocale(i18n.language), + const dateFormatter = useMemo( + () => createDateFormatter(i18n.language, { dateStyle: 'long' }), [i18n.language] ); - const dateFormatter = useMemo(() => { - try { - return new Intl.DateTimeFormat(normalizedLocale, { - dateStyle: 'long', - }); - } catch (error) { - console.error('Unsupported locale for blog post date formatting', error); - return new Intl.DateTimeFormat('en-US', { dateStyle: 'long' }); - } - }, [normalizedLocale]); - const { data: post, isLoading, From f3372743614e7994b4999c2ebfe59ed30e0a7603 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 20:16:56 +0000 Subject: [PATCH 3/4] Create reusable PageBreadcrumb component - Add PageBreadcrumb component to reduce breadcrumb duplication - Update Contact.tsx, Blog.tsx, Solutions.tsx, Projects.tsx to use PageBreadcrumb - Update blog/[slug].tsx and solutions/[slug].tsx to use PageBreadcrumb with intermediate items - Remove ~150 lines of duplicated breadcrumb code across 6 pages Co-authored-by: marcelo-m7 <117441129+marcelo-m7@users.noreply.github.com> --- src/components/PageBreadcrumb.tsx | 61 +++++++++++++++++++++++++++++++ src/pages/Blog.tsx | 25 +------------ src/pages/Contact.tsx | 42 ++------------------- src/pages/Projects.tsx | 25 +------------ src/pages/Solutions.tsx | 25 +------------ src/pages/blog/[slug].tsx | 34 +++-------------- src/pages/solutions/[slug].tsx | 34 +++-------------- 7 files changed, 80 insertions(+), 166 deletions(-) create mode 100644 src/components/PageBreadcrumb.tsx diff --git a/src/components/PageBreadcrumb.tsx b/src/components/PageBreadcrumb.tsx new file mode 100644 index 0000000..be690e4 --- /dev/null +++ b/src/components/PageBreadcrumb.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { + Breadcrumb, + BreadcrumbList, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbPage, + BreadcrumbSeparator, +} from '@/components/ui/breadcrumb'; + +interface PageBreadcrumbProps { + /** + * The current page title, will be shown as the last breadcrumb item + */ + currentPage: string; + /** + * Optional additional breadcrumb items between home and current page + */ + items?: Array<{ + label: string; + href: string; + }>; +} + +/** + * A reusable breadcrumb component for pages + * Always includes Home as the first item and current page as the last + */ +export const PageBreadcrumb = ({ currentPage, items = [] }: PageBreadcrumbProps) => { + const { t } = useTranslation(); + + return ( +

+ + + + + {t('navigation.home')} + + + + {items.map((item, index) => ( + + + + {item.label} + + + + + ))} + + {currentPage} + + + +
+ ); +}; diff --git a/src/pages/Blog.tsx b/src/pages/Blog.tsx index 6f4b957..af76848 100644 --- a/src/pages/Blog.tsx +++ b/src/pages/Blog.tsx @@ -5,6 +5,7 @@ import { Button } from '@/components/ui/button'; import Layout from '@/components/Layout'; import Meta from '@/components/Meta'; import NewsletterSection from '@/components/NewsletterSection'; +import { PageBreadcrumb } from '@/components/PageBreadcrumb'; import { ArrowRight, Clock, @@ -15,14 +16,6 @@ import { import { supabase } from '@/integrations/supabase'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; -import { - Breadcrumb, - BreadcrumbList, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbPage, - BreadcrumbSeparator, -} from '@/components/ui/breadcrumb'; import { Pagination, PaginationContent, @@ -226,21 +219,7 @@ const Blog = () => { ogDescription={t('blog.description')} ogImage="/placeholder.svg" /> -
- - - - - {t('navigation.home')} - - - - - {t('navigation.blog')} - - - -
+
diff --git a/src/pages/Contact.tsx b/src/pages/Contact.tsx index d4bca40..4a28387 100644 --- a/src/pages/Contact.tsx +++ b/src/pages/Contact.tsx @@ -5,19 +5,11 @@ import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import Layout from '@/components/Layout'; import Meta from '@/components/Meta'; +import { PageBreadcrumb } from '@/components/PageBreadcrumb'; import { Mail, Phone, MapPin, Send, CheckCircle } from 'lucide-react'; import { supabase } from '@/integrations/supabase'; import { useToast } from '@/hooks/use-toast'; import { useTranslation } from 'react-i18next'; -import { Link } from 'react-router-dom'; -import { - Breadcrumb, - BreadcrumbList, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbPage, - BreadcrumbSeparator, -} from '@/components/ui/breadcrumb'; import { useQuery } from '@tanstack/react-query'; import { normalizeToStringArray } from '@/lib/utils'; @@ -261,21 +253,7 @@ const Contact = () => { ogDescription={t('contact.description')} ogImage="/placeholder.svg" /> -
- - - - - {t('navigation.home')} - - - - - {t('navigation.contact')} - - - -
+
@@ -308,21 +286,7 @@ const Contact = () => { ogDescription={t('contact.description')} ogImage="/placeholder.svg" /> -
- - - - - {t('navigation.home')} - - - - - {t('navigation.contact')} - - - -
+ {/* Hero Section */}
diff --git a/src/pages/Projects.tsx b/src/pages/Projects.tsx index 503100c..c4516ae 100644 --- a/src/pages/Projects.tsx +++ b/src/pages/Projects.tsx @@ -3,17 +3,10 @@ import { useQuery } from '@tanstack/react-query'; import { Github, ExternalLink, Calendar, ArrowRight } from 'lucide-react'; import Layout from '../components/Layout'; import Meta from '@/components/Meta'; +import { PageBreadcrumb } from '@/components/PageBreadcrumb'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; -import { - Breadcrumb, - BreadcrumbList, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbPage, - BreadcrumbSeparator, -} from '@/components/ui/breadcrumb'; import { supabase } from '@/integrations/supabase'; import { useTranslation, Trans } from 'react-i18next'; import { Link } from 'react-router-dom'; @@ -228,21 +221,7 @@ const Projects = () => { ogDescription={t('projects.description')} ogImage="/placeholder.svg" /> -
- - - - - {t('navigation.home')} - - - - - {t('navigation.projects')} - - - -
+
diff --git a/src/pages/Solutions.tsx b/src/pages/Solutions.tsx index 596f39f..8972bf6 100644 --- a/src/pages/Solutions.tsx +++ b/src/pages/Solutions.tsx @@ -3,15 +3,8 @@ import { useQuery } from '@tanstack/react-query'; import { Button } from '@/components/ui/button'; import Layout from '@/components/Layout'; import Meta from '@/components/Meta'; +import { PageBreadcrumb } from '@/components/PageBreadcrumb'; import { Link } from 'react-router-dom'; -import { - Breadcrumb, - BreadcrumbList, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbPage, - BreadcrumbSeparator, -} from '@/components/ui/breadcrumb'; import { ArrowRight } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { supabase } from '@/integrations/supabase'; @@ -109,21 +102,7 @@ const Solutions = () => { ogDescription={t('solutionsPage.description')} ogImage="/placeholder.svg" /> -
- - - - - {t('navigation.home')} - - - - - {t('navigation.solutions')} - - - -
+ {/* Hero Section */}
diff --git a/src/pages/blog/[slug].tsx b/src/pages/blog/[slug].tsx index 989b7b9..b9600fb 100644 --- a/src/pages/blog/[slug].tsx +++ b/src/pages/blog/[slug].tsx @@ -7,17 +7,10 @@ import Layout from '@/components/Layout'; import Meta from '@/components/Meta'; import NewsletterSection from '@/components/NewsletterSection'; import CommentsSection from '@/components/blog/CommentsSection'; +import { PageBreadcrumb } from '@/components/PageBreadcrumb'; import { supabase } from '@/integrations/supabase'; import { createDateFormatter } from '@/lib/i18n'; import type { Database } from '@/integrations/supabase/types'; -import { - Breadcrumb, - BreadcrumbList, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbPage, - BreadcrumbSeparator, -} from '@/components/ui/breadcrumb'; type BlogPost = Database['public']['Tables']['blog_posts']['Row']; @@ -325,27 +318,10 @@ const BlogPostPage = () => { ogDescription={metaDescription} ogImage={metaImage} /> -
- - - - - {t('navigation.home')} - - - - - - {t('navigation.blog')} - - - - - {post.title} - - - -
+
{ ogDescription={displaySolution.description} ogImage={displaySolution.imageUrl ?? '/placeholder.svg'} /> -
- - - - - {t('navigation.home')} - - - - - - {t('navigation.solutions')} - - - - - {displaySolution.title} - - - -
+
From 4e23fad21476c5e7ea9046876161caee70ffde21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 20:19:30 +0000 Subject: [PATCH 4/4] Fix unused index parameter in PageBreadcrumb - Remove unused index parameter from map callback in PageBreadcrumb component Co-authored-by: marcelo-m7 <117441129+marcelo-m7@users.noreply.github.com> --- src/components/PageBreadcrumb.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PageBreadcrumb.tsx b/src/components/PageBreadcrumb.tsx index be690e4..a4de8bd 100644 --- a/src/components/PageBreadcrumb.tsx +++ b/src/components/PageBreadcrumb.tsx @@ -41,7 +41,7 @@ export const PageBreadcrumb = ({ currentPage, items = [] }: PageBreadcrumbProps) - {items.map((item, index) => ( + {items.map((item) => (