Skip to content

Commit

Permalink
Merge pull request #3500 from ever-co/feat/offline-mode-handling
Browse files Browse the repository at this point in the history
[Feat]: Implement Automatic Offline Page Display
  • Loading branch information
evereq authored Jan 8, 2025
2 parents 04ecaf8 + 75eaa3d commit 65c4a41
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 20 deletions.
19 changes: 11 additions & 8 deletions apps/web/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { PropsWithChildren, useEffect } from 'react';

import { useCheckAPI } from '@app/hooks/useCheckAPI';
import GlobalSkeleton from '@components/ui/global-skeleton';
import OfflineWrapper from '@components/offline-wrapper';
import { JitsuOptions } from '@jitsu/jitsu-react/dist/useJitsu';

import { PHProvider } from './integration/posthog/provider';
Expand Down Expand Up @@ -145,14 +146,16 @@ const LocaleLayout = ({ children, params: { locale }, pageProps }: PropsWithChil
enableSystem
disableTransitionOnChange
>
{loading && !pathname?.startsWith('/auth') ? (
<GlobalSkeleton />
) : (
<>
<AppState />
<JitsuRoot pageProps={pageProps}>{children}</JitsuRoot>
</>
)}
<OfflineWrapper>
{loading && !pathname?.startsWith('/auth') ? (
<GlobalSkeleton />
) : (
<>
<AppState />
<JitsuRoot pageProps={pageProps}>{children}</JitsuRoot>
</>
)}
</OfflineWrapper>
</ThemeProvider>
</Provider>
</NextAuthSessionProvider>
Expand Down
18 changes: 6 additions & 12 deletions apps/web/app/[locale]/page-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@

'use client';
import React, { useEffect, useState } from 'react';
import { useOrganizationTeams, useTimerView } from '@app/hooks';
import { useOrganizationTeams } from '@app/hooks';
import { clsxm } from '@app/utils';
import NoTeam from '@components/pages/main/no-team';
import { withAuthentication } from 'lib/app/authenticator';
import { Breadcrumb, Card, Container } from 'lib/components';
import { AuthUserTaskInput, TeamInvitations, TeamMembers, Timer, UnverifiedEmail } from 'lib/features';
import { MainLayout } from 'lib/layout';
import { IssuesView } from '@app/constants';
import { useNetworkState } from '@uidotdev/usehooks';
import Offline from '@components/pages/offline';
import { useTranslations } from 'next-intl';

import { Analytics } from '@vercel/analytics/react';
Expand All @@ -34,7 +32,6 @@ function MainPage() {
const t = useTranslations();
const [headerSize] = useState(10);
const { isTeamMember, isTrackingEnabled, activeTeam } = useOrganizationTeams();
const { timerStatus } = useTimerView();

const [fullWidth, setFullWidth] = useAtom(fullWidthState);
const [view, setView] = useAtom(headerTabs);
Expand All @@ -44,7 +41,7 @@ function MainPage() {
{ title: activeTeam?.name || '', href: '/' },
{ title: t(`common.${view}`), href: `/` }
];
const { online } = useNetworkState();

useEffect(() => {
if (view == IssuesView.KANBAN && path == '/') {
setView(IssuesView.CARDS);
Expand All @@ -57,27 +54,24 @@ function MainPage() {
setFullWidth(JSON.parse(window?.localStorage.getItem('conf-fullWidth-mode') || 'true'));
}, [setFullWidth]);

if (!online) {
return <Offline showTimer={timerStatus?.running} />;
}
return (
<>
<div className="flex flex-col justify-between h-full min-h-screen">
{/* <div className="flex-grow "> */}
{/* <div className="flex-grow"> */}
<MainLayout
showTimer={headerSize <= 11.8 && isTrackingEnabled}
className="h-full"
mainHeaderSlot={
<div className="bg-white dark:bg-dark-high">
<div className={clsxm('bg-white dark:bg-dark-high ', !fullWidth && 'x-container')}>
<div className="mx-8-container my-3 !px-0 flex flex-row items-start justify-between ">
<div className="flex items-center justify-center h-10 gap-8">
<div className="flex gap-8 justify-center items-center h-10">
<PeoplesIcon className="text-dark dark:text-[#6b7280] h-6 w-6" />

<Breadcrumb paths={breadcrumb} className="text-sm" />
</div>

<div className="flex items-center justify-center h-10 gap-1 w-max">
<div className="flex gap-1 justify-center items-center w-max h-10">
<HeaderTabs linkAll={false} />
</div>
</div>
Expand All @@ -100,7 +94,7 @@ function MainPage() {
footerClassName={clsxm('')}
>
<ChatwootWidget />
<div className="h-full ">{isTeamMember ?
<div className="h-full">{isTeamMember ?
<Container fullWidth={fullWidth} className='mx-auto' >
<TeamMembers kanbanView={view} />
</Container>
Expand Down
37 changes: 37 additions & 0 deletions apps/web/components/offline-wrapper/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use client';

import { useNetworkState } from '@uidotdev/usehooks';
import Offline from '@components/pages/offline';
import { useTimerView } from '@app/hooks';
import { usePathname } from 'next/navigation';

interface OfflineWrapperProps {
children: React.ReactNode;
}

/**
* A wrapper component that conditionally renders the Offline component if the user is not online.
* The Offline component is not shown on authentication pages (paths starting with /auth).
* When the user is offline, the Offline component is rendered with the showTimer prop set to
* whether the timer is running or not.
*
* @example
* <OfflineWrapper>
* <MyComponent />
* </OfflineWrapper>
* @param {React.ReactNode} children - The children components to render when the user is online
* @returns {React.ReactElement} - The Offline component if the user is offline (except on auth pages), or the children components if the user is online
*/
export default function OfflineWrapper({ children }: OfflineWrapperProps) {
const { online } = useNetworkState();
const { timerStatus } = useTimerView();
const pathname = usePathname();

const isAuthPage = pathname?.startsWith('/auth');

if (!online && !isAuthPage) {
return <Offline showTimer={timerStatus?.running} />;
}

return <>{children}</>;
}
3 changes: 3 additions & 0 deletions apps/web/components/pages/offline/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import { cn } from '@/lib/utils';
import SadCry from '@components/ui/svgs/sad-cry';
import { Text } from 'lib/components';
import { useTranslations } from 'next-intl';

interface IPropsOffline {
showTimer?: boolean
}

function Offline({ showTimer }: IPropsOffline) {
const t = useTranslations();

return (
<div className="mt-28 flex flex-col gap-7 items-center">
<div className="m-auto relative flex justify-center items-center gap-4 text-center ">
Expand Down

0 comments on commit 65c4a41

Please sign in to comment.