feat: wire Footer contact info to live site content
This commit is contained in:
@@ -1,12 +1,44 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { MemoryRouter } from 'react-router-dom'
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
const singleMock = vi.fn()
|
||||
const eqMock = vi.fn(() => ({ single: singleMock }))
|
||||
const selectMock = vi.fn(() => ({ eq: eqMock }))
|
||||
const fromMock = vi.fn<(table: string) => { select: typeof selectMock }>(() => ({ select: selectMock }))
|
||||
|
||||
vi.mock('../lib/supabase', () => ({
|
||||
supabase: { from: (table: string) => fromMock(table) },
|
||||
}))
|
||||
vi.mock('../lib/resolveImageUrl', () => ({
|
||||
resolveImageUrl: (path: string) => path,
|
||||
}))
|
||||
|
||||
const SITE_CONTENT_ROW = {
|
||||
id: 'default',
|
||||
hero_headline: 'Vos cheveux, votre couronne',
|
||||
hero_tagline: 'Coiffures protectrices par Mira',
|
||||
about_bio: '',
|
||||
about_portrait_image: '',
|
||||
contact_email: 'hello@braidsbymira.com',
|
||||
contact_hours: 'Mar–Sam, 9h à 18h',
|
||||
}
|
||||
|
||||
import Footer from './Footer'
|
||||
|
||||
describe('Footer', () => {
|
||||
it('renders contact info and quick links', () => {
|
||||
beforeEach(() => {
|
||||
singleMock.mockReset().mockResolvedValue({ data: SITE_CONTENT_ROW, error: null })
|
||||
eqMock.mockClear()
|
||||
selectMock.mockClear()
|
||||
fromMock.mockClear()
|
||||
})
|
||||
|
||||
it('renders contact info and quick links from site content', async () => {
|
||||
render(<MemoryRouter><Footer /></MemoryRouter>)
|
||||
expect(screen.getAllByText(/braids by mira/i).length).toBeGreaterThan(0)
|
||||
expect(await screen.findByRole('link', { name: 'hello@braidsbymira.com' })).toHaveAttribute('href', 'mailto:hello@braidsbymira.com')
|
||||
expect(screen.getByText('Mar–Sam, 9h à 18h')).toBeInTheDocument()
|
||||
expect(screen.getByRole('link', { name: /boutique/i })).toHaveAttribute('href', '/shop')
|
||||
expect(screen.getByRole('link', { name: /règlements/i })).toHaveAttribute('href', '/rules')
|
||||
})
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { fetchSiteContent, type SiteContent } from '../data/siteContent'
|
||||
import styles from './Footer.module.css'
|
||||
|
||||
function Footer() {
|
||||
const [content, setContent] = useState<SiteContent | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
async function load() {
|
||||
try {
|
||||
setContent(await fetchSiteContent())
|
||||
} catch {
|
||||
// Footer content is non-critical; leave contact info blank on failure
|
||||
// rather than surfacing an error on every single page.
|
||||
}
|
||||
}
|
||||
void load()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<footer className={styles.footer}>
|
||||
<div className={styles.inner}>
|
||||
@@ -12,8 +28,12 @@ function Footer() {
|
||||
|
||||
<div className={styles.column}>
|
||||
<p className={styles.columnTitle}>Contact</p>
|
||||
<a href="mailto:hello@braidsbymira.com">hello@braidsbymira.com</a>
|
||||
<p>Mar–Sam, 9h à 18h</p>
|
||||
{content && (
|
||||
<>
|
||||
<a href={`mailto:${content.contactEmail}`}>{content.contactEmail}</a>
|
||||
<p>{content.contactHours}</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.column}>
|
||||
|
||||
Reference in New Issue
Block a user