mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 06:43:06 +00:00
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).
79 lines
2.3 KiB
TypeScript
79 lines
2.3 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useState } from 'react'
|
|
|
|
const COPY_FEEDBACK_RESET_MS = 2000
|
|
|
|
export type CopyFeedback = 'idle' | 'copied' | 'error'
|
|
|
|
/**
|
|
* C194 — what is being copied changes the wording. `link` is the share
|
|
* controls' default; `text` serves the reel transcript.
|
|
*/
|
|
export type CopySubject = 'link' | 'text'
|
|
|
|
const copyFeedbackLabelsBySubject: Record<CopySubject, Record<CopyFeedback, string>> = {
|
|
link: {
|
|
idle: 'Copiar link',
|
|
copied: 'Link copiado',
|
|
error: 'Não foi possível copiar',
|
|
},
|
|
text: {
|
|
idle: 'Copiar texto',
|
|
copied: 'Texto copiado',
|
|
error: 'Não foi possível copiar',
|
|
},
|
|
}
|
|
|
|
const copyFeedbackLiveMessagesBySubject: Record<CopySubject, Record<CopyFeedback, string>> = {
|
|
link: {
|
|
idle: '',
|
|
copied: 'Link copiado.',
|
|
error: 'Não foi possível copiar o link.',
|
|
},
|
|
text: {
|
|
idle: '',
|
|
copied: 'Texto copiado.',
|
|
error: 'Não foi possível copiar o texto.',
|
|
},
|
|
}
|
|
|
|
export const copyFeedbackLabelsFor = (subject: CopySubject): Record<CopyFeedback, string> =>
|
|
copyFeedbackLabelsBySubject[subject]
|
|
|
|
export const copyFeedbackLiveMessagesFor = (subject: CopySubject): Record<CopyFeedback, string> =>
|
|
copyFeedbackLiveMessagesBySubject[subject]
|
|
|
|
/** The link wording the existing share controls import (unchanged). */
|
|
export const copyFeedbackLabels = copyFeedbackLabelsBySubject.link
|
|
export const copyFeedbackLiveMessages = copyFeedbackLiveMessagesBySubject.link
|
|
|
|
/**
|
|
* The one copy-to-clipboard feedback contract of the share controls (C166 share
|
|
* sheet, C167 cut share kit): the label per state, the screen-reader live
|
|
* message and the auto-reset. `copy` never throws — a denied clipboard is the
|
|
* `error` state — and answers whether the text landed, so a caller that counts
|
|
* the action (C213's share-by-link) only counts a real copy.
|
|
*/
|
|
export const useCopyFeedback = () => {
|
|
const [feedback, setFeedback] = useState<CopyFeedback>('idle')
|
|
|
|
useEffect(() => {
|
|
if (feedback === 'idle') return
|
|
const reset = setTimeout(() => setFeedback('idle'), COPY_FEEDBACK_RESET_MS)
|
|
return () => clearTimeout(reset)
|
|
}, [feedback])
|
|
|
|
const copy = async (text: string): Promise<boolean> => {
|
|
try {
|
|
await navigator.clipboard.writeText(text)
|
|
setFeedback('copied')
|
|
return true
|
|
} catch {
|
|
setFeedback('error')
|
|
return false
|
|
}
|
|
}
|
|
|
|
return { feedback, copy }
|
|
}
|