teableio/teable

View on GitHub
apps/nextjs-app/src/pages/_app.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
import * as Sentry from '@sentry/nextjs';
import type { IUser } from '@teable/sdk';
import dayjs from 'dayjs';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
import type { AppContext, AppProps as NextAppProps } from 'next/app';
import App from 'next/app';
import Head from 'next/head';
import { appWithTranslation } from 'next-i18next';
import { useEffect } from 'react';
import { z } from 'zod';
import { Guide } from '@/components/Guide';
import { MicrosoftClarity, Umami } from '@/components/Metrics';
import RouterProgressBar from '@/components/RouterProgress';
import type { IServerEnv } from '@/lib/server-env';
import type { NextPageWithLayout } from '@/lib/type';
import { colors } from '@/themes/colors';
import { getColorsCssVariablesText } from '@/themes/utils';
import nextI18nextConfig from '../../next-i18next.config.js';
import { AppProviders } from '../AppProviders';
import '@glideapps/glide-data-grid/dist/index.css';
dayjs.extend(utc);
dayjs.extend(timezone);
extendZodWithOpenApi(z);

/**
 * Import global styles, global css or polyfills here
 * i.e.: import '@/assets/theme/style.scss'
 */
import '../styles/global.css';

import '@fontsource-variable/inter';

// Workaround for https://github.com/zeit/next.js/issues/8592
export type AppProps<T> = NextAppProps<T> & {
  /** Will be defined only is there was an error */
  err?: Error;
};

type AppPropsWithLayout = AppProps<{ user?: IUser; env?: IServerEnv; err?: Error }> & {
  Component: NextPageWithLayout;
};

/**
 * @link https://nextjs.org/docs/advanced-features/custom-app
 */
const MyApp = (appProps: AppPropsWithLayout) => {
  const { Component, err, pageProps } = appProps;
  const { user, env = {}, err: pageErr } = pageProps;
  // Use the layout defined at the page level, if available
  const getLayout = Component.getLayout ?? ((page) => page);
  useEffect(() => {
    Sentry.setUser(user ? { id: user.id, email: user.email } : null);
  }, [user]);

  return (
    <>
      <AppProviders env={env}>
        <Head>
          <meta
            name="viewport"
            content="width=device-width,viewport-fit=cover, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
          />
          <style>{getColorsCssVariablesText(colors)}</style>
        </Head>
        <MicrosoftClarity clarityId={env.microsoftClarityId} user={user} />
        <Umami umamiWebSiteId={env.umamiWebSiteId} umamiUrl={env.umamiUrl} user={user} />
        <script
          dangerouslySetInnerHTML={{
            __html: `
              window.version="${process.env.NEXT_PUBLIC_BUILD_VERSION ?? 'develop'}";
              window.__TE__=${JSON.stringify(env)};
            `,
          }}
        />
        {/* Workaround for https://github.com/vercel/next.js/issues/8592 */}
        {getLayout(<Component {...pageProps} err={err || pageErr} />, { ...pageProps })}
      </AppProviders>
      {user && <Guide user={user} />}
      <RouterProgressBar />
    </>
  );
};

/**
 * Generally don't enable getInitialProp if you don't need to,
 * all your pages will be served server-side (no static optimizations).
 */

MyApp.getInitialProps = async (appContext: AppContext) => {
  // calls page's `getInitialProps` and fills `appProps.pageProps`
  const appProps = await App.getInitialProps(appContext);
  return { ...appProps };
};

export default appWithTranslation(MyApp, {
  ...nextI18nextConfig,
});