ekzyis 3a7c3f7af2
Add setting to send diagnostics back to SN (#463)
* Add diagnostics settings & endpoint

Stackers can now help us to identify and fix bugs by enabling diagnostics.

This will send anonymized data to us.

For now, this is only used to send events around push notifications.

* Send diagnostics to slack

* Detect OS

* Diagnostics data is only pseudonymous, not anonymous

It's only pseudonymous since with additional knowledge (which stacker uses which fancy name), we could trace the events back to individual stackers.

Data is only anonymous if this is not possible - it must be irreversible.

* Check if window.navigator is defined

* Use Slack SDK

* Catch errors of slack requests

---------

Co-authored-by: ekzyis <ek@stacker.news>
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
2023-09-18 18:00:16 -05:00

116 lines
3.9 KiB
JavaScript

import '../styles/globals.scss'
import { ApolloProvider, gql } from '@apollo/client'
import { MeProvider } from '../components/me'
import PlausibleProvider from 'next-plausible'
import getApolloClient from '../lib/apollo'
import { PriceProvider } from '../components/price'
import { BlockHeightProvider } from '../components/block-height'
import Head from 'next/head'
import { useRouter } from 'next/dist/client/router'
import { useEffect } from 'react'
import { ShowModalProvider } from '../components/modal'
import ErrorBoundary from '../components/error-boundary'
import { LightningProvider } from '../components/lightning'
import { ToastProvider } from '../components/toast'
import { ServiceWorkerProvider } from '../components/serviceworker'
import { SSR } from '../lib/constants'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { LoggerProvider } from '../components/logger'
NProgress.configure({
showSpinner: false
})
function writeQuery (client, apollo, data) {
if (apollo && data) {
client.writeQuery({
query: gql`${apollo.query}`,
data,
variables: apollo.variables,
overwrite: SSR,
broadcast: false
})
}
}
function MyApp ({ Component, pageProps: { ...props } }) {
const client = getApolloClient()
const router = useRouter()
useEffect(() => {
const nprogressStart = (_, { shallow }) => !shallow && NProgress.start()
const nprogressDone = (_, { shallow }) => !shallow && NProgress.done()
router.events.on('routeChangeStart', nprogressStart)
router.events.on('routeChangeComplete', nprogressDone)
router.events.on('routeChangeError', nprogressDone)
if (!props?.apollo) return
// HACK: 'cause there's no way to tell Next to skip SSR
// So every page load, we modify the route in browser history
// to point to the same page but without SSR, ie ?nodata=true
// this nodata var will get passed to the server on back/foward and
// 1. prevent data from reloading and 2. perserve scroll
// (2) is not possible while intercepting nav with beforePopState
router.replace({
pathname: router.pathname,
query: { ...router.query, nodata: true }
}, router.asPath, { ...router.options, shallow: true }).catch((e) => {
// workaround for https://github.com/vercel/next.js/issues/37362
if (!e.cancelled) {
console.log(e)
throw e
}
})
return () => {
router.events.off('routeChangeStart', nprogressStart)
router.events.off('routeChangeComplete', nprogressDone)
router.events.off('routeChangeError', nprogressDone)
}
}, [router.asPath, props?.apollo])
/*
If we are on the client, we populate the apollo cache with the
ssr data
*/
const { apollo, ssrData, me, price, blockHeight, ...otherProps } = props
useEffect(() => {
writeQuery(client, apollo, ssrData)
}, [client, apollo, ssrData])
return (
<>
<Head>
<meta name='viewport' content='initial-scale=1.0, width=device-width' />
</Head>
<ErrorBoundary>
<PlausibleProvider domain='stacker.news' trackOutboundLinks>
<ApolloProvider client={client}>
<MeProvider me={me}>
<LoggerProvider>
<ServiceWorkerProvider>
<PriceProvider price={price}>
<LightningProvider>
<ToastProvider>
<ShowModalProvider>
<BlockHeightProvider blockHeight={blockHeight}>
<Component ssrData={ssrData} {...otherProps} />
</BlockHeightProvider>
</ShowModalProvider>
</ToastProvider>
</LightningProvider>
</PriceProvider>
</ServiceWorkerProvider>
</LoggerProvider>
</MeProvider>
</ApolloProvider>
</PlausibleProvider>
</ErrorBoundary>
</>
)
}
export default MyApp