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/typesAssim, 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.monetizationpara 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.
