Add social sharing buttons and QR code for events
Public event page:
- Share buttons: X (Twitter), Facebook, Instagram (copy link), TikTok (copy link), copy link
- Buttons use url_encode for share URLs with event title + URL
- Instagram/TikTok copy to clipboard (no direct share URL support)
- Consistent brutal design with aria-labels
Organizer dashboard:
- Share X, Facebook, copy link buttons per event in events list
- QR code download button per event
- Route /mon-compte/evenement/{id}/qrcode: generates 400px PNG QR code via Endroid
- QR code points to public event URL, downloaded as qrcode-{slug}.png
JS module:
- assets/modules/share.js: initShare() handles data-share-copy buttons
- Copies URL to clipboard, shows checkmark for 1.5s then restores icon
- 4 tests (no buttons, copy, checkmark restore, multiple buttons)
Social icons already displayed via _social_icons.html.twig component
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
75
tests/js/share.test.js
Normal file
75
tests/js/share.test.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
||||
import { initShare } from '../../assets/modules/share.js'
|
||||
|
||||
describe('initShare', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = ''
|
||||
})
|
||||
|
||||
it('does nothing without share buttons', () => {
|
||||
expect(() => initShare()).not.toThrow()
|
||||
})
|
||||
|
||||
it('copies URL to clipboard on click', async () => {
|
||||
document.body.innerHTML = `
|
||||
<button data-share-copy="https://example.com/event/1">
|
||||
<svg class="icon"></svg>
|
||||
</button>
|
||||
`
|
||||
|
||||
const writeText = vi.fn().mockResolvedValue(undefined)
|
||||
globalThis.navigator = { clipboard: { writeText } }
|
||||
|
||||
initShare()
|
||||
document.querySelector('[data-share-copy]').click()
|
||||
|
||||
await new Promise(r => setTimeout(r, 10))
|
||||
|
||||
expect(writeText).toHaveBeenCalledWith('https://example.com/event/1')
|
||||
})
|
||||
|
||||
it('shows checkmark after copy then restores', async () => {
|
||||
vi.useFakeTimers()
|
||||
|
||||
document.body.innerHTML = `
|
||||
<button data-share-copy="https://example.com">
|
||||
<svg class="original"></svg>
|
||||
</button>
|
||||
`
|
||||
|
||||
globalThis.navigator = { clipboard: { writeText: vi.fn().mockResolvedValue(undefined) } }
|
||||
|
||||
initShare()
|
||||
const btn = document.querySelector('[data-share-copy]')
|
||||
const originalHtml = btn.innerHTML
|
||||
btn.click()
|
||||
|
||||
await vi.advanceTimersByTimeAsync(100)
|
||||
|
||||
expect(btn.innerHTML).toContain('M5 13l4 4L19 7')
|
||||
|
||||
vi.advanceTimersByTime(1500)
|
||||
|
||||
expect(btn.innerHTML).toBe(originalHtml)
|
||||
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('handles multiple share buttons', async () => {
|
||||
document.body.innerHTML = `
|
||||
<button data-share-copy="https://a.com"><svg></svg></button>
|
||||
<button data-share-copy="https://b.com"><svg></svg></button>
|
||||
`
|
||||
|
||||
const writeText = vi.fn().mockResolvedValue(undefined)
|
||||
globalThis.navigator = { clipboard: { writeText } }
|
||||
|
||||
initShare()
|
||||
|
||||
document.querySelectorAll('[data-share-copy]')[1].click()
|
||||
|
||||
await new Promise(r => setTimeout(r, 10))
|
||||
|
||||
expect(writeText).toHaveBeenCalledWith('https://b.com')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user