Web Monetization: Parte 2 - Verificar atividade
Por Ciaran Edwards(Traduzido por Rute Correia)
Depois de configurar o apontador de pagamentos, a próxima coisa a fazer é verificar se estamos a receber pagamentos através de Web Monetization e responder a isso, usando a API de JavaScript.
Apesar de bastar algo como document.monetization === 'started'
para fazer essa verificação, se estivermos a usar uma framework como React, convém que a página atualize sempre que o processo de pagamento inicie ou termine.
💡 O nosso sítio web está construído em React, pelo que as amostras de código usam React. Os princípios são bastante simples, contudo. Por isso, não deverá ser demasiado difícil de afinar o código para que encaixe em qualquer framework que esteja a ser usada.
Passo 0: Avisar o TypeScript do Web Monetization
Caso esteja a ser usado TypeScript, é preciso avisá-lo que o document
agora tem uma propriedade, monetization
. Ou, mais especificamente, que pode ter uma propriedade monetization
. Felizmente para nós, a Coil criou um pacote com todos os tipos necessários à implementação do Web Monetization. Vamos instalá-lo:
npm install --save-dev @webmonetization/types
Assim, podemos adicionar a propriedade monetization
à interface global do Document
interface, deste modo:
import { MonetizationObject } from '@webmonetization/types'
declare global {
interface Document {
monetization?: MonetizationObject
}
}
Agora, o TypeScript já sabe que existe Web Monetization! 🎉
Passo 1: Adicionar ouvintes de eventos
Para descobrir se há eventos de monetização a acontecer, pode-se usar document.monetization.addEventListener
.
document.monetization.addEventListener(eventName, (event) => {
doSomeStuff(event)
})
No entanto, é preciso ter em atenção duas coisas:
- Antes de tentarmos adicionar ouvintes de eventos, temos sempre de verificar se existe
document.monetization
para podermos adicioná-los. - Devemos certificar-nos que removemos o ouvinte do evento, quando já não estamos a usá-lo.
Então, vamos criar uma função que resolva ambas as questões:
import {
MonetizationEventMap,
MonetizationEventType,
} from '@webmonetization/types'
import { TEventListener } from '@webmonetization/types/build/genericEventListeners'
/**
* Isto adiciona um ouvinte do evento de monetização e devolve uma função
* que podemos chamar para removê-lo mais tarde
*/
const addEventListener = <TEvent extends MonetizationEventType>(
event: TEvent,
eventListener: TEventListener<MonetizationEventMap[TEvent]>,
): (() => void) => {
document.monetization?.addEventListener(event, eventListener, {
passive: true,
})
return () => document.monetization?.removeEventListener(event, eventListener)
}
Isto vai dar jeito quando adicionarmos ouvintes de eventos com useEffect
– podemos adicionar um ouvinte e depois removê-lo com uma função de limpeza:
useEffect(() => {
const removeListener = addEventListener('monetizationprogress', (event) => {
console.log('Check out all this cash money 💸', event.detail)
})
return () => {
removeEventListener()
}
}, [])
Passo 2: Armazenar o estado atual do Web Monetization num estado global
Agora que já sabemos verificar quando estamos a receber pagamentos, queremos que os componentes do nosso sítio web reajam sempre que os pagamentos comecem ou parem. Para este exemplo, vamos usar a Context API do React.
Primeiro, criamos o contexto:
import React from 'react'
import { MonetizationState } from '@webmonetization/types'
type WebMonetizationContextValue = {
state: MonetizationState // "pending" | "started" | "stopped"
}
const WebMonetizationContext = React.createContext<
WebMonetizationContextValue | undefined
>(undefined)
Inicializar o contexto com undefined
é um pequeno truque que uso para ter a certeza que não tento aceder ao WebMonetizationContext
acidentalmente, fora do Provider
. Se definires um valor padrão ao usar o React Context, podes esquecer-te de encapsular a tua aplicação com o componente Provider
sem nunca te aperceberes. Já me aconteceu ser apanhado em coisas assim algumas vezes, por isso permito que o valor esteja undefined
, e depois crio um hook que dispara um erro se o valor do contexto estiver em falta.
export const useWebMonetization = (): WebMonetizationContextValue => {
const webMonetizationContext = useContext(WebMonetizationContext)
if (!webMonetizationContext) {
throw new Error(
`[WebMonetizationContext] You're using the context outside of the WebMonetizationProvider 😬`,
)
}
return webMonetizationContext
}
O próximo passo é fazer o nosso componente personalizado WebMonetizationProvider
. É aí que vamos configurar os nossos ouvintes de evento para acompanhar o estado atual de monetização, e depois definir o valor do nosso WebMonetizationContext
.
export const WebMonetizationProvider: React.FC = ({ children }) => {
const [state, setState] = useState<MonetizationState>('pending')
useEffect(() => {
const onStart = () => setState('started')
const onStop = () => setState('stopped')
const events = [
addEventListener('monetizationstart', onStart),
addEventListener('monetizationprogress', onStart),
addEventListener('monetizationstop', onStop),
]
return () => {
events.forEach((removeListener) => removeListener())
}
}, [setState])
return (
<WebMonetizationContext.Provider value={{ state }}>
{children}
</WebMonetizationContext.Provider>
)
}
A única coisa que falta é encapsular a aplicação com WebMonetizationProvider
, e está tudo pronto para que possas começar a usar o context
nos teus componentes.
Passo 3: Reagir a eventos de monetização
Agora que a nossa aplicação está configurada para acompanhar eventos de monetização, provavelmente só há mais um pormenor que nos interessa: "Está ligado ou não?"
Vamos criar mais um hook para verificar isso mesmo:
export const useIsWebMonetizationActive = (): boolean => {
const { state } = useWebMonetization()
return state === 'started'
}
Podes usar este hook em qualquer componente para verificar se é para mostrar conteúdo adicional, desativar anúncios ou qualquer outra coisa que queiras oferecer a visitantes que usem o protocolo Web Monetization.
No Interruptor, estamos só a começar a implementar isto. Por isso, para já, temos apenas um componente WebMonetizationToaster
que mostra uma notificação a dizer "Obrigado" quando o Web Monetization está ativo.
import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { toast } from 'react-toastify'
import { AnalyticsEvent, trackEvent } from 'utils/analytics'
import { useIsWebMonetizationActive } from 'utils/monetization'
export const WebMonetizationToaster: React.FC = () => {
const { t } = useTranslation('monetization')
const isMonetizationActive = useIsWebMonetizationActive()
useEffect(() => {
if (!isMonetizationActive) return
// Show the thank-you message
toast.success(t('thanks'))
}, [isMonetizationActive, t])
useEffect(() => {
if (!isMonetizationActive) return
// Send an event to Plausible so we can see how many visitors use it
trackEvent(AnalyticsEvent.WEB_MONETIZATION_ACTIVE)
}, [isMonetizationActive])
return null
}
E parece-se assim:
Para já, é tudo o que temos, mas vamos desenvolver novas funcionalidades nos próximos meses e escrever sobre elas aqui - por isso, não percas o próximo artigo.