While having teams and organizations is an essential SaaS feature where users can share assets and resources with teammates, not every SaaS needs it.
In fact, many have asked me how to remove organizations and only keep individual users. So, in this recipe, I will write down my thoughts on removing organizations from your project.
There are two main ways to remove organizations:
- The more challenging way is refactoring the project and removing the code related to
organizations
- The second and more straightforward way is to keep
organizations
, while hiding all the related UI. In this way, each user belongs to their organization. This way is more future-proof: if your SaaS will need refactoring for adding teammates to your user's accounts, the code is still there, and you will only need to show it.
Since the first way is highly challenging and will cause problems pulling changes from the latest version, I suggest you try the second solution: we will create organizations behind the scenes for each user, but these won't be shown in the front end.
Here is the list of changes we need to add:
- Skip onboarding: automatically create an Organization for the user
- Remove Organizations dropdown from the headers
- Remove the "Organization" tab within the settings pages
The above should take you less than 2 minutes to implement. Let's get started!
NB: This post is specific to the Next.js Firebase SaaS Kit. With that said - the same concepts apply to the others, but you need to find the equivalent files and components.
Skipping the Onboarding flow
You can change the onboarding flow and add your own steps if you need your users to set up their accounts. The organization, though, will be created without user input.
Let's update the Onboarding
page at pages/onboarding/index.tsx
. First, we will predefine the onboarding values, so that the form can easily be skipped. To do so, we will update the defaultValues
object of the useForm
hook:
const Onboarding = () => { const currentStep = 2; const organization = `Organization`; // or whatever you want to call it const form = useForm({ defaultValues: { data: { organization, invites: [] as Invite[], }, currentStep }, }); // ... more code here};
As you can see from the above, we predefined the organization
value. This will be used to create the organization behind the scenes. Additionally, by setting the currentStep
to 2
, we will skip the first two steps of the onboarding flow.
This will automatically kick off the onboarding API request and create an organization named Organization
.
Redirecting to Dashboard
We also want to redirect users away from the onboarding flow. To do so, we will update the CompleteOnboardingStep
at src/components/onboarding/CompleteOnboardingStep.tsx
.
import { useRouter } from 'next/router';export const CompleteOnboardingStep: React.FCC<{ data: CompleteOnboardingStepData;}> = ({ data }) => { const router = useRouter(); const { trigger, error, data: response } = useCompleteOnboardingRequest(); const onboardingCompleteRequested = useRef(false); useEffect(() => { void (async () => { // React will run the effect twice // so we use the ref to prevent it if (!onboardingCompleteRequested.current) { onboardingCompleteRequested.current = true; const result = await trigger(data); if (result.returnUrl) { router.replace(result.returnUrl) } } })(); }, [data, router, trigger]); // ...
In the above we added the router.replace
function to redirect the user to the dashboard.
- First you need to import
useRouter
fromnext/router
at the top of the file - Then, we inject the
router
using theuseRouter
hook - Finally, we use
router.replace
to navigate to the dashboard once the onboarding flow is complete
Hiding the Organizations dropdown
To hide the organizations dropdown, we will update the headers of the layout you have chosen to use.
Sidebar Layout
If you have chosen the sidebar layout, open the component AppSidebar.tsx
at src/components/layouts/sidebar/AppSidebar.tsx
and remove the code below:
<SidebarContent className={'mt-4'}> <OrganizationsSelector displayName={!ctx.collapsed} /></SidebarContent>
In this way - the user will never see the organizations dropdown.
You can replace the above with your Logo importing the component Logo
from src/core/ui/Logo.tsx
.
<SidebarContent className={'mt-4'}> <Logo /></SidebarContent>
Header Layout
If you are using the header layout, you need to remove the organizations dropdown from the header.
Open the component AppHeaderWithMenu
at src/components/layouts/header/AppHeaderWithMenu.tsx
and remove the component rendered by the constant OrganizationsDropdown
:
<div className={'hidden lg:flex'}> <OrganizationsSelector displayName={true} /></div>
Removing the Settings pages
Finally, we want to remove the settings pages. To do so, we need to first remove them from the settings navigation menu:
We open the component SettingsPageContainer.tsx
and then remove the organization settings from the links
array:
const links = [ { path: '/settings/profile', i18n: 'common:profileSettingsTabLabel', }, // remove the object below! { path: '/settings/organization', i18n: 'common:organizationSettingsTabLabel', }, { path: '/settings/subscription', i18n: 'common:subscriptionSettingsTabLabel', },];
Optionally, remove the pages at settings/organization
.
Alternatively, you can automatically redirect them somewhere else using the getServerSideProps
function on each page:
export function getServerSideProps(ctx) { return ctx.redirect(configuration.paths.appHome);}
Removing Organizations Page from Main Sidebar
To remove the Organizations page from the main sidebar, open the config src/navigation.config.tsx
and remove the object pointing to the organizations page.
Updating the Firestore Rules
Finally, remove the rules to create new organizations in Firestore rules. You should only allow to read from them:
match /organizations/{organizationId} { allow read: if userId() in existingData().members;}
Final thoughts
That's it! While your application will still create an organization for each user, these do not exist as far as your SaaS users are concerned.
In terms of future-proofing, hiding organizations allows you to add them in the longer term if users need a way to share stuff with teammates.