firecmsco / firecms

Awesome Firebase/Firestore-based CMS. The missing admin panel for your Firebase project!
https://firecms.co
Other
1.13k stars 185 forks source link

Custom setup with FireCMS compontent does not register basePath #561

Closed andreassh closed 1 month ago

andreassh commented 11 months ago

Hi, First thanks for an awesome project. Very happy this exists out there.

I'm following the guides regarding Custom CMSApp and Using FireCMS with NextJS and I'm running into some problem with the home / <FireCMSHomePage /> component route

I'm using the following basePath: '/cms' on the component, but Navigation doesn't seem to register the route as my home path. Whenever I hit http://localhost:3000/cms I get the following page:

Screenshot 2023-09-27 at 10 11 55

If i hit "Back to Home" button, I'm send to '/', the app renders the <FireCMSHomePage> component and routing works fine from then on. Expect for the "Home" link in the header which goes to http://localhost:3000/cms, as it should, but that of course sends be back to the "Page not found" screen

The home link in the left navigation goes to http://localhost:3000 and works, even though this is not the desired behaviour.

Screenshot 2023-09-27 at 10 05 26 Screenshot 2023-09-27 at 10 05 21

I'm rendering the <FireCMS> component like in the guide, but with basePath and baseCollectionPath set to "/cms". Setting basePath seems to have no effect at all

<FireCMS
            basePath="/cms"
            baseCollectionPath={"/cms"}
            authController={authController}
            collections={collections}
            dataSource={dataSource}
            storageSource={storageSource}
            entityLinkBuilder={({ entity }) =>
              `https://console.firebase.google.com/project/${firebaseApp.options.projectId}/firestore/data/${entity.path}/${entity.id}`
            } >

If i try the same setup with <FirebaseCMSApp> component instead, routing works fine.

<FirebaseCMSApp
      name={"My Online Shop"}
      basePath={"/cms"}
      authentication={myAuthenticator}
      collections={[productsCollection]}
      firebaseConfig={firebaseConfig}
    />

This is my full <CMS> component setup:

"use client";

import React, { useCallback, useMemo } from "react";

import "typeface-rubik";
import "@fontsource/ibm-plex-mono";

import {
  Authenticator,
  CircularProgressCenter,
  createCMSDefaultTheme,
  FirebaseAuthController,
  FirebaseLoginView,
  FireCMS,
  ModeControllerProvider,
  NavigationRoutes,
  Scaffold,
  SideDialogs,
  SnackbarProvider,
  useBuildModeController,
  useFirebaseAuthController,
  useFirebaseStorageSource,
  useInitialiseFirebase,
  useValidateAuthenticator,
} from "firecms";
import { firebaseConfig } from "./firebase-config";

import { productsCollection } from "./collections/userInfos";
import { GoogleAuthProvider, User as FirebaseUser } from "firebase/auth";
import { BrowserRouter as Router } from "react-router-dom";
import { CssBaseline, ThemeProvider } from "@mui/material";
import { useCustomDatasource } from "./dateSources";

const DEFAULT_SIGN_IN_OPTIONS = [GoogleAuthProvider.PROVIDER_ID];

/** Add collections here */
const collections = [productsCollection];

/**
 * This is an example of how to use the components provided by FireCMS for
 * a better customisation.
 * @constructor
 */
export default function CMS() {
  const signInOptions = DEFAULT_SIGN_IN_OPTIONS;

  const authenticator: Authenticator<FirebaseUser> = useCallback(
    async ({ user, authController }) => {
      if (user?.email?.includes("flanders")) {
        throw Error("Stupid Flanders!");
      }

      console.log("Allowing access to", user?.email);
      // This is an example of retrieving async data related to the user
      // and storing it in the controller's extra field.
      const sampleUserRoles = await Promise.resolve(["admin"]);
      authController.setExtra(sampleUserRoles);

      return true;
    },
    []
  );

  const {
    firebaseApp,
    firebaseConfigLoading,
    configError,
    firebaseConfigError,
  } = useInitialiseFirebase({ firebaseConfig });

  const authController: FirebaseAuthController = useFirebaseAuthController({
    firebaseApp,
    signInOptions,
  });

    // using custom data source to fetch data from other places than firestore
  const dataSource = useCustomDatasource({
    firebaseApp,
    // You can add your `FirestoreTextSearchController` here
  });

  const storageSource = useFirebaseStorageSource({ firebaseApp });

  const modeController = useBuildModeController();
  const theme = useMemo(
    () => createCMSDefaultTheme({ mode: modeController.mode }),
    []
  );

  const { authLoading, canAccessMainView, notAllowedError } =
    useValidateAuthenticator({
      authController,
      authentication: authenticator,
      dataSource,
      storageSource,
    });

  if (configError) {
    return <div> {configError} </div>;
  }

  if (firebaseConfigError) {
    return (
      <div>
        It seems like the provided Firebase config is not correct. If you are
        using the credentials provided automatically by Firebase Hosting, make
        sure you link your Firebase app to Firebase Hosting.
      </div>
    );
  }

  if (firebaseConfigLoading || !firebaseApp) {
    return <CircularProgressCenter />;
  }

  return (
    <Router>
      <SnackbarProvider>
        <ModeControllerProvider value={modeController}>
          <FireCMS
            basePath="/cms"
            baseCollectionPath={"/cms"}
            authController={authController}
            collections={collections}
            dataSource={dataSource}
            storageSource={storageSource}
            entityLinkBuilder={({ entity }) =>
              `https://console.firebase.google.com/project/${firebaseApp.options.projectId}/firestore/data/${entity.path}/${entity.id}`
            }
          >
            {({ context, loading }) => {
              console.log("context", context);
              let component;
              if (loading) {
                component = <CircularProgressCenter />;
              } else if (!canAccessMainView) {
                component = (
                  <FirebaseLoginView
                    allowSkipLogin={false}
                    signInOptions={signInOptions}
                    firebaseApp={firebaseApp}
                    authController={authController}
                  />
                );
              } else {
                component = (
                  <Scaffold name={"CMS"}>
                    <NavigationRoutes />
                    <SideDialogs />
                  </Scaffold>
                );
              }

              return (
                <ThemeProvider theme={theme}>
                  <CssBaseline />
                  {component}
                </ThemeProvider>
              );
            }}
          </FireCMS>
        </ModeControllerProvider>
      </SnackbarProvider>
    </Router>
  );
}

And these are my dependencies:

"dependencies": {
    "@emotion/react": "^11.11.1",
    "@emotion/styled": "^11.11.0",
    "@mui/icons-material": "^5",
    "@mui/lab": "^5.0.0-alpha.145",
    "@mui/material": "^5",
    "@mui/x-date-pickers": "^5.0.0-beta.1",
    "@types/node": "20.6.5",
    "@types/react": "18.2.22",
    "@types/react-dom": "18.2.7",
    "eslint": "8.50.0",
    "eslint-config-next": "13.5.2",
    "firebase": "^9",
    "firecms": "^2.0.0",
    "next": "13.5.2",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-router": "^6",
    "react-router-dom": "^6",
    "typescript": "5.2.2"
  },

Any ideas? Thanks in advance

fgatti675 commented 1 month ago

Hi @andreassh pretty alte, but this should be fixed in the latest V3 releases :)