Next.js Discord

Discord Forum

Detect when user is online

Unanswered
Northeast Congo Lion posted this in #help-forum
Open in Discord
Northeast Congo LionOP
I'm building a dashboard with nextjs 14.2.5 and I want to know whether the user is online or not before making requests. Something like in Youtube where there's a layout with a retry button to test if he's online and a little toast that says "user back online".
I made several attempts but I don't know how to make it work and even structure it.
My approach was to have a general error boundary for that and a component client side component that checks the network status.
This is what i did.

20 Replies

Northeast Congo LionOP
full-page-network-error.tsx
'use client'

import { useEffect, useState } from 'react'
import { isOnline } from '@/lib/utils'
import { Button } from '../ui/button'
import Link from 'next/link'
import { Routes } from '@/app/routes'
import { toast } from 'sonner'

interface ErrorBoundaryProps {
  error: Error & { digest?: string }
  reset: () => void
}

export function FullPageErrorBoundary({ error, reset }: ErrorBoundaryProps) {
  const [isNetworkError, setIsNetworkError] = useState(false)

  useEffect(() => {
    const handleNetworkChange = () => {
      setIsNetworkError(!navigator.onLine)
    }

    window.addEventListener('online', handleNetworkChange)
    window.addEventListener('offline', handleNetworkChange)

    setIsNetworkError(!navigator.onLine)

    return () => {
      window.removeEventListener('online', handleNetworkChange)
      window.removeEventListener('offline', handleNetworkChange)
    }
  }, [])

  const handleRetry = () => {
    if (navigator.onLine) {
      reset() // Rerun the action after the network is back
    } else {
      toast.error('Réseau indisponible') // Show error if network is still down
    }
  }

  return (
    <div className="flex min-h-screen flex-col items-center justify-center">
      <h2 className="mb-4 text-2xl font-bold">Oops! Une erreur est survenue</h2>
      <p className="mb-4 text-gray-600">
        {isNetworkError
          ? 'Il semble que vous êtes hors-ligne. Vérifier votre connexion internet.'
          : 'Nous avons des difficultés à charger cette page. Veuillez réessayer.'}
      </p>
      <Button onClick={handleRetry} className="">
        Réessayer
      </Button>
      <Button variant={'link'} className="mt-4 hover:underline" asChild>
        <Link href={Routes.HOME}>Aller à l&apos;accueil</Link>
      </Button>
    </div>
  )
}
Here's the status-bar.tsx
'use client'

import { useState, useEffect } from 'react'
import { isOnline } from '@/lib/utils'

export default function NetworkStatusBar() {
  const [online, setOnline] = useState(true)
  const [visible, setVisible] = useState(false)

  useEffect(() => {
    const updateOnlineStatus = () => {
      const status = isOnline()
      setOnline(status)
      setVisible(!status)
    }

    window.addEventListener('online', updateOnlineStatus)
    window.addEventListener('offline', updateOnlineStatus)

    return () => {
      window.removeEventListener('online', updateOnlineStatus)
      window.removeEventListener('offline', updateOnlineStatus)
    }
  }, [])

  useEffect(() => {
    if (online && visible) {
      const timer = setTimeout(() => setVisible(false), 3000)
      return () => clearTimeout(timer)
    }
  }, [online, visible])

  if (!visible) return null

  return (
    <div
      className={`fixed left-0 right-0 top-0 p-2 text-center text-sm ${online ? 'bg-green-500' : 'bg-red-500'} text-white transition-all duration-300`}>
      {online ? 'Back online' : 'You are currently offline'}
    </div>
  )
}
And then I have this error.tsx at the root of my project:
'use client'

import { FullPageErrorBoundary } from '@/components/network-status/full-page-network-error'
import { useEffect } from 'react'

export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  useEffect(() => {
    // Log the error to an error reporting service
    console.error(error)
  }, [error])

  return <FullPageErrorBoundary error={error} reset={reset} />
}


My assumption was, the precedence of error boundaries will make it work since the error is specific to the network. So i created other error.tsx files in subfolders to catch other nested errors.
Please help make it work, using while using maybe a better structure for my error handling files.
Daggertooth pike conger
@Northeast Congo Lion im not sure exactly what you mean, but use the online event and when its triggered you just display a you are online toast?
Northeast Congo LionOP
I will try that way.

I thought about how the online status is use in other web apps.
Basically what i want to achieve is, if the user is offline there's a big component that renders and prompts the user to try again.

While he's still offline he can't used the app (in Youtube for example you don't have results and there's an illustration that says you're offline with a retry button).
So I thought about using a global error boundary since it has already that logic of error and retry. But in my attempt, the error boundary never shows up, it's swallowed by nested error boundaries. So maybe my thinking process about how to achieve is wrong that's why I asked if it's a structural (the fact that I'm using error boundaries and how I use them) or a implementation problem (maybe I used the wrong API or the logic isn't good).
Northeast Congo LionOP
Ok I get it, thanks!
On it
@Northeast Congo Lion Ok I get it, thanks! On it
Daggertooth pike conger
howd it go
Northeast Congo LionOP
Works like a charm, thanks a lot!
I think I overengineered it with error boundaries when it wasn't necessary
Northeast Congo LionOP
Northeast Congo LionOP
The second part of my question is for this component (like in the image, which says "Connect to the Internet") with a retry button.
It made me immediately think of error boundaries, so I made a global one, based on the network status but it doesn't show up when I need it to.
I dont know if it's because I have other error boundaries defined. But i want it to behave like in the Youtube app.

For example right now, in my server components when i fetch data if I dont get the actual result I return something like "Something wrong happened", and that's what is shown to the user. The problem is that I want the text "Something wrong happened" to be shown only when there is something other than a network error.

How would go about it ?
Northeast Congo LionOP
Now that you said this 😓
It will work but... maybe you're missing the retry button ?