teqo-backup/src/components/CopyLinkButton.tsx
Francisco Solla f47c2645ac feat(C213): contadores anônimos de circulação por peça na Central de Conteúdos (Closes #1258)
Collection contentEvent (hidden, sem hooks, sem PII) + beacon público
POST /api/content-events fail-soft, download contado no servidor na rota
de mídia, agregação em uma query group-by e a coluna "Circulação" na lista
interna + painel na ficha (port classe-a-classe do artefato estendido,
crítica final do designer certificada).
2026-09-23 15:29:43 -03:00

60 lines
1.8 KiB
TypeScript

'use client'
import { CheckIcon, CopyIcon } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { copyFeedbackLabels, copyFeedbackLiveMessages, useCopyFeedback } from '@/lib/copyFeedback'
import { cn } from '@/lib/utils'
type CopyLinkButtonProps = {
/** Absolute URL or a same-origin path — resolved against the current origin on click. */
url: string
variant?: 'default' | 'outline' | 'ghost'
className?: string
/**
* Called only when the text actually landed in the clipboard (C213 counts the
* share-by-link of a piece). The control itself never counts: it is shared
* with the cut surfaces.
*/
onCopied?: () => void
}
/**
* The one copy-to-clipboard control of the cut surfaces (public page, result
* card, library): same feedback label/auto-reset and screen-reader live region.
* A relative path is resolved against the current origin on click, so a server
* component can pass `publicPath` directly.
*/
export const CopyLinkButton = ({
url,
variant = 'outline',
className,
onCopied,
}: CopyLinkButtonProps) => {
const { feedback, copy } = useCopyFeedback()
return (
<>
<Button
type="button"
variant={variant}
className={cn('min-h-10', className)}
onClick={() => {
void copy(new URL(url, window.location.origin).toString()).then((copied) => {
if (copied) onCopied?.()
})
}}
>
{feedback === 'copied' ? (
<CheckIcon data-icon="inline-start" aria-hidden="true" />
) : (
<CopyIcon data-icon="inline-start" aria-hidden="true" />
)}
{copyFeedbackLabels[feedback]}
</Button>
<span aria-live="polite" className="sr-only">
{copyFeedbackLiveMessages[feedback]}
</span>
</>
)
}