-
-
Notifications
You must be signed in to change notification settings - Fork 408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Split dashboard routes into individual pages #10632
base: main
Are you sure you want to change the base?
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
4cb8572
to
eecc8a2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work overall, this will be a great improvement.
I think we should review how we load the default sections, and ideally skip doing it in middleware to prevent another server roundtrip with the query to figure out default section before the page is loaded, with data we then discard. This query also currently misses to check preview features and redirect to Overview for those that have enabled that.
I played around a bit with a solution where the index pages for /dashboard/index.tsx
instead loads the default sections and renders the correct one, and also used imported and used the same page in in a new route /dashboard/[slug]/index.tsx
.
This also prevents a client side redirect from /dashboard/index.tsx
when switching accounts, and prevents a loading indicator on the account switcher pill.
/dashboard/index.tsx
(also imported and exported in /dashboard/[slug]/index.tsx
)
import React from 'react';
import { useQuery } from '@apollo/client';
import type { NextPageContext } from 'next';
import { useRouter } from 'next/router';
import { isHostAccount, isIndividualAccount } from '../../lib/collective';
import roles from '../../lib/constants/roles';
import { API_V2_CONTEXT } from '../../lib/graphql/helpers';
import useLoggedInUser from '../../lib/hooks/useLoggedInUser';
import { PREVIEW_FEATURE_KEYS } from '../../lib/preview-features';
import { ALL_SECTIONS, ROOT_SECTIONS } from '../../components/dashboard/constants';
import DashboardPage from '../../components/dashboard/DashboardPage';
import { adminPanelQuery } from '../../components/dashboard/queries';
import AllCollectives from '../../components/dashboard/sections/collectives/AllCollectives';
import HostExpenses from '../../components/dashboard/sections/expenses/HostDashboardExpenses';
import ReceivedExpenses from '../../components/dashboard/sections/expenses/ReceivedExpenses';
import Overview from '../../components/dashboard/sections/overview/Overview';
import type { DashboardSectionProps } from '../../components/dashboard/types';
import MessageBoxGraphqlError from '../../components/MessageBoxGraphqlError';
export default function DashboardIndexPage({ lastWorkspaceVisit }) {
const router = useRouter();
const { LoggedInUser } = useLoggedInUser();
const querySlug = Array.isArray(router.query.slug) ? router.query.slug[0] : router.query.slug;
const activeSlug = querySlug || lastWorkspaceVisit?.slug || LoggedInUser?.collective.slug;
const { data, error } = useQuery(adminPanelQuery, {
context: API_V2_CONTEXT,
variables: { slug: activeSlug },
skip: !activeSlug || !LoggedInUser,
});
const account = data?.account;
const defaultSection = getDefaultSectionForAccount(account, LoggedInUser);
const Component: React.FC<DashboardSectionProps> = getComponentForDefaultSection(defaultSection);
React.useEffect(() => {
if (!activeSlug) {
router.replace('/');
} else if (defaultSection === ALL_SECTIONS.PAYMENT_RECEIPTS) {
router.replace(`/dashboard/${activeSlug}/${defaultSection}`);
}
}, [LoggedInUser, activeSlug, defaultSection, router]);
if (Component) {
return <DashboardPage Component={Component} slug={activeSlug} section={defaultSection} />;
}
return (
<DashboardPage
Component={error ? () => <MessageBoxGraphqlError error={error} /> : () => <div />}
slug={activeSlug}
section={null}
/>
);
}
function getComponentForDefaultSection(section) {
switch (section) {
case ALL_SECTIONS.OVERVIEW:
return Overview;
case ALL_SECTIONS.EXPENSES:
return ReceivedExpenses;
case ALL_SECTIONS.HOST_EXPENSES:
return HostExpenses;
case ROOT_SECTIONS.ALL_COLLECTIVES:
return AllCollectives;
default:
return null;
}
}
function getDefaultSectionForAccount(account, loggedInUser) {
if (!account) {
return null;
} else if (account.type === 'ROOT') {
return ROOT_SECTIONS.ALL_COLLECTIVES;
} else if (
isIndividualAccount(account) ||
(!isHostAccount(account) && loggedInUser.hasPreviewFeatureEnabled(PREVIEW_FEATURE_KEYS.COLLECTIVE_OVERVIEW))
) {
return ALL_SECTIONS.OVERVIEW;
} else if (isHostAccount(account)) {
return ALL_SECTIONS.HOST_EXPENSES;
} else {
const isAdmin = loggedInUser?.isAdminOfCollective(account);
const isAccountant = loggedInUser?.hasRole(roles.ACCOUNTANT, account);
return !isAdmin && isAccountant ? ALL_SECTIONS.PAYMENT_RECEIPTS : ALL_SECTIONS.EXPENSES;
}
}
function getLastWorkspaceVisitClient() {
if (typeof document !== 'undefined') {
const valStr = document.cookie
.split('; ')
.find(row => row.startsWith('lastWorkspaceVisit='))
?.split('=')[1];
if (valStr) {
try {
return JSON.parse(valStr);
} catch {
return null;
}
}
}
}
function getLastWorkspaceVisitServer(ctx: NextPageContext) {
if ((ctx.req as any).cookies.lastWorkspaceVisit) {
try {
return JSON.parse((ctx.req as any).cookies.lastWorkspaceVisit);
} catch {
return null;
}
}
}
DashboardIndexPage.getInitialProps = ctx => {
const lastWorkspaceVisit = ctx.req ? getLastWorkspaceVisitServer(ctx) : getLastWorkspaceVisitClient();
return {
lastWorkspaceVisit,
};
};
}, | ||
{ | ||
source: | ||
'/dashboard/:slug/:section(goals|connected-accounts|export|for-developers|user-security|custom-email|activity-log|collective-page|authorized-apps|advanced|webhooks|sending-money|policies|receiving-money|tiers|tickets|host|info|gift-cards|gift-cards-create|payment-methods|payment-receipts|fiscal-hosting|security|host-virtual-cards-settings)/:subpath*', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tiers is now a "proper" section
'/dashboard/:slug/:section(goals|connected-accounts|export|for-developers|user-security|custom-email|activity-log|collective-page|authorized-apps|advanced|webhooks|sending-money|policies|receiving-money|tiers|tickets|host|info|gift-cards|gift-cards-create|payment-methods|payment-receipts|fiscal-hosting|security|host-virtual-cards-settings)/:subpath*', | |
'/dashboard/:slug/:section(goals|connected-accounts|export|for-developers|user-security|custom-email|activity-log|collective-page|authorized-apps|advanced|webhooks|sending-money|policies|receiving-money|tickets|host|info|gift-cards|gift-cards-create|payment-methods|payment-receipts|fiscal-hosting|security|host-virtual-cards-settings)/:subpath*', |
{ | ||
source: '/dashboard/:slug', | ||
destination: '/dashboard', | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If adding a /dashboard/[slug]/index.tsx
route we can skip this (and prevent that client side redirect)
{ | |
source: '/dashboard/:slug', | |
destination: '/dashboard', | |
}, |
We should also rebase this, there is now a |
Split the dashboard route into individual pages.
Reduces bundle sizes to load each dashboard tool (see before and after).
WIP
Before
Route (pages) Size First Load JS
┌ ƒ / 263 B 538 kB
├ /_app 0 B 441 kB
├ ƒ /404 2.19 kB 520 kB
├ ƒ /accept-financial-contributions 21.5 kB 892 kB
├ ƒ /api/connected-accounts/[service]/callback 0 B 441 kB
├ ƒ /api/connected-accounts/[service]/oauthUrl 0 B 441 kB
├ ƒ /api/docs/search 0 B 441 kB
├ ƒ /api/download-file 0 B 441 kB
├ ƒ /api/github-repositories 0 B 441 kB
├ ƒ /api/graphql/v1 0 B 441 kB
├ ƒ /api/graphql/v2 0 B 441 kB
├ ƒ /api/legacy/button 0 B 441 kB
├ ƒ /api/legacy/contribute 0 B 441 kB
├ ƒ /api/legacy/widget 0 B 441 kB
├ ƒ /api/robots 0 B 441 kB
├ ƒ /api/users/exchange-login-token 0 B 441 kB
├ ƒ /api/users/exists 0 B 441 kB
├ ƒ /api/users/refresh-token 0 B 441 kB
├ ƒ /api/users/signin 0 B 441 kB
├ ƒ /api/users/two-factor-auth 0 B 441 kB
├ ƒ /api/users/update-token 0 B 441 kB
├ ƒ /applications 5.7 kB 569 kB
├ ƒ /banner-iframe 7.85 kB 487 kB
├ ƒ /become-a-host 6.33 kB 529 kB
├ ƒ /become-a-sponsor 7.44 kB 525 kB
├ ƒ /button 794 B 441 kB
├ ƒ /collective-contact 2.52 kB 869 kB
├ ƒ /collective-page 48.5 kB 984 kB
├ ƒ /collectives 10.1 kB 532 kB
├ ƒ /collectives-iframe 5.04 kB 454 kB
├ ƒ /confirm-guest 3.94 kB 521 kB
├ ƒ /confirmCollectiveDeletion 3.13 kB 521 kB
├ ƒ /confirmEmail 3.48 kB 521 kB
├ ƒ /confirmOrder 6.43 kB 569 kB
├ ƒ /contribute 12.3 kB 872 kB
├ ƒ /contribution-flow 3.31 kB 817 kB
├ ƒ /conversation 6.65 kB 953 kB
├ ƒ /conversations 5.01 kB 865 kB
├ ƒ /create-collective 3.02 kB 684 kB
├ ƒ /create-conversation 6.21 kB 872 kB
├ ƒ /create-expense 10.6 kB 1.02 MB
├ ƒ /create-fund 13.6 kB 594 kB
├ ƒ /create-project 3.67 kB 870 kB
├ ƒ /createEvent 10.8 kB 905 kB
├ ƒ /createOrganization 14.2 kB 700 kB
├ ƒ /dashboard 598 kB 1.82 MB
├ ƒ /e2c 7.5 kB 530 kB
├ ƒ /embed/contribution-flow 2.33 kB 816 kB
├ ƒ /expense 3.07 kB 1.04 MB
├ ƒ /expenses 10.3 kB 1.06 MB
├ ƒ /external-redirect 3.68 kB 557 kB
├ ƒ /fiscal-hosting 10 kB 532 kB
├ ƒ /guest-join 5.82 kB 523 kB
├ ƒ /help-and-support 19.1 kB 722 kB
├ ƒ /home 219 B 538 kB
├ ƒ /how-it-works 6.08 kB 528 kB
├ ƒ /manage-contributions 5.84 kB 895 kB
├ ƒ /marketingPage 78 kB 592 kB
├ ƒ /member-invitations 8.14 kB 594 kB
├ ƒ /oauth/authorize 8.37 kB 581 kB
├ ƒ /order 5.92 kB 877 kB
├ ƒ /orders 12.7 kB 883 kB
├ ƒ /osc-host-application 26.2 kB 697 kB
├ ƒ /preview/[accountSlug]/[[...path]] 367 B 756 kB
├ ƒ /preview/[accountSlug]/support/[[...path]] 387 B 756 kB
├ ƒ /pricing 10.5 kB 528 kB
├ ƒ /redeem 19.7 kB 673 kB
├ ƒ /redeemed 5.98 kB 580 kB
├ ƒ /reset-password 6.22 kB 513 kB
├ ƒ /reset-password-completed 2.68 kB 520 kB
├ ƒ /reset-password-sent 3.12 kB 557 kB
├ ƒ /search 18.4 kB 589 kB
├ ƒ /signin 5.5 kB 555 kB
├ ƒ /signinLinkSent 3.21 kB 557 kB
├ ƒ /staticPage 28.1 kB 545 kB
├ ƒ /submitted-expenses 8.89 kB 1.06 MB
├ ƒ /terms-of-fiscal-sponsorship 742 B 441 kB
├ ƒ /tier 11.4 kB 883 kB
├ ƒ /transactions 19.6 kB 879 kB
├ ƒ /unsubscribeEmail 2.87 kB 520 kB
├ ƒ /update 5.42 kB 952 kB
├ ƒ /updatePaymentMethod 12.1 kB 575 kB
├ ƒ /updates 10.7 kB 870 kB
└ ƒ /welcome 6.63 kB 570 kB
├ chunks/appCommon-b8bd914fb84b2229.js 285 kB
├ chunks/framework-91261ea7164be8bd.js 66.8 kB
├ chunks/main-1a3c32dd0473688b.js 36.9 kB
├ chunks/pages/_app-16446b6da4e9b6f8.js 49 kB
├ css/720497e76efea6ff.css 18.8 kB
└ other shared chunks (total) 9.58 kB
ƒ Middleware 51.8 kB
ƒ (Dynamic) server-rendered on demand
After
Route (pages) Size First Load JS
┌ ƒ / 261 B 538 kB
├ /_app 0 B 441 kB
├ ƒ /404 2.19 kB 519 kB
├ ƒ /accept-financial-contributions 23.7 kB 896 kB
├ ƒ /api/connected-accounts/[service]/callback 0 B 441 kB
├ ƒ /api/connected-accounts/[service]/oauthUrl 0 B 441 kB
├ ƒ /api/docs/search 0 B 441 kB
├ ƒ /api/download-file 0 B 441 kB
├ ƒ /api/github-repositories 0 B 441 kB
├ ƒ /api/graphql/v1 0 B 441 kB
├ ƒ /api/graphql/v2 0 B 441 kB
├ ƒ /api/legacy/button 0 B 441 kB
├ ƒ /api/legacy/contribute 0 B 441 kB
├ ƒ /api/legacy/widget 0 B 441 kB
├ ƒ /api/robots 0 B 441 kB
├ ƒ /api/users/exchange-login-token 0 B 441 kB
├ ƒ /api/users/exists 0 B 441 kB
├ ƒ /api/users/refresh-token 0 B 441 kB
├ ƒ /api/users/signin 0 B 441 kB
├ ƒ /api/users/two-factor-auth 0 B 441 kB
├ ƒ /api/users/update-token 0 B 441 kB
├ ƒ /applications 4.04 kB 568 kB
├ ƒ /banner-iframe 7.72 kB 487 kB
├ ƒ /become-a-host 6.33 kB 528 kB
├ ƒ /become-a-sponsor 7.43 kB 524 kB
├ ƒ /button 794 B 441 kB
├ ƒ /collective-contact 5.11 kB 874 kB
├ ƒ /collective-page 57.7 kB 990 kB
├ ƒ /collectives 10.1 kB 532 kB
├ ƒ /collectives-iframe 5.04 kB 454 kB
├ ƒ /confirm-guest 3.93 kB 521 kB
├ ƒ /confirmCollectiveDeletion 3.12 kB 520 kB
├ ƒ /confirmEmail 3.48 kB 520 kB
├ ƒ /confirmOrder 4.81 kB 568 kB
├ ƒ /contribute 18 kB 876 kB
├ ƒ /contribution-flow 3.31 kB 817 kB
├ ƒ /conversation 11.6 kB 957 kB
├ ƒ /conversations 11.2 kB 869 kB
├ ƒ /create-collective 3.01 kB 683 kB
├ ƒ /create-conversation 8.57 kB 877 kB
├ ƒ /create-expense 13.2 kB 1.02 MB
├ ƒ /create-fund 12.8 kB 593 kB
├ ƒ /create-project 6.13 kB 875 kB
├ ƒ /createEvent 17 kB 909 kB
├ ƒ /createOrganization 14.2 kB 698 kB
├ ƒ /dashboard 28.8 kB 1.13 MB
├ ƒ /dashboard/[slug]/accounts/[[...subpath]] 18.3 kB 660 kB
├ ƒ /dashboard/[slug]/chart-of-accounts 19.1 kB 738 kB
├ ƒ /dashboard/[slug]/contributors 10.4 kB 650 kB
├ ƒ /dashboard/[slug]/expected-funds 563 B 960 kB
├ ƒ /dashboard/[slug]/expenses 2.64 kB 1.11 MB
├ ƒ /dashboard/[slug]/host-agreements 21.5 kB 729 kB
├ ƒ /dashboard/[slug]/host-applications 21.3 kB 682 kB
├ ƒ /dashboard/[slug]/host-expenses 9.3 kB 1.11 MB
├ ƒ /dashboard/[slug]/host-tax-forms 22 kB 690 kB
├ ƒ /dashboard/[slug]/host-transactions/[[...subpath]] 528 B 995 kB
├ ƒ /dashboard/[slug]/host-virtual-card-requests 26.4 kB 713 kB
├ ƒ /dashboard/[slug]/host-virtual-cards 18.3 kB 751 kB
├ ƒ /dashboard/[slug]/hosted-collectives/[[...subpath]] 2.54 kB 923 kB
├ ƒ /dashboard/[slug]/incoming-contributions 535 B 960 kB
├ ƒ /dashboard/[slug]/invoices-receipts 10.9 kB 642 kB
├ ƒ /dashboard/[slug]/legacy-settings-sections/[section] 700 B 1.25 MB
├ ƒ /dashboard/[slug]/notifications/[[...subpath]] 11.1 kB 615 kB
├ ƒ /dashboard/[slug]/orders 554 B 960 kB
├ ƒ /dashboard/[slug]/outgoing-contributions 533 B 960 kB
├ ƒ /dashboard/[slug]/reports/[[...subpath]] 21.8 kB 1.02 MB
├ ƒ /dashboard/[slug]/submitted-expenses 25.3 kB 1.13 MB
├ ƒ /dashboard/[slug]/tax-information 17.9 kB 698 kB
├ ƒ /dashboard/[slug]/team 12.2 kB 686 kB
├ ƒ /dashboard/[slug]/tickets 622 B 1.25 MB
├ ƒ /dashboard/[slug]/tiers 616 B 1.25 MB
├ ƒ /dashboard/[slug]/transactions 11.4 kB 918 kB
├ ƒ /dashboard/[slug]/updates/[[...subpath]] 12.4 kB 723 kB
├ ƒ /dashboard/[slug]/vendors 34.9 kB 730 kB
├ ƒ /dashboard/[slug]/virtual-cards 9.76 kB 726 kB
├ ƒ /dashboard/root/account-settings 6.38 kB 680 kB
├ ƒ /dashboard/root/account-type 6.41 kB 680 kB
├ ƒ /dashboard/root/activity-log 5.69 kB 722 kB
├ ƒ /dashboard/root/all-collectives 2.91 kB 924 kB
├ ƒ /dashboard/root/ban-account 470 B 681 kB
├ ƒ /dashboard/root/clear-cache 7.87 kB 681 kB
├ ƒ /dashboard/root/connect-accounts 5.77 kB 679 kB
├ ƒ /dashboard/root/host-transactions 12.6 kB 920 kB
├ ƒ /dashboard/root/merge-accounts 7.22 kB 681 kB
├ ƒ /dashboard/root/move-authored-contributions 495 B 681 kB
├ ƒ /dashboard/root/move-expenses 7.41 kB 681 kB
├ ƒ /dashboard/root/move-received-contributions 496 B 681 kB
├ ƒ /dashboard/root/recurring-contributions 11.9 kB 713 kB
├ ƒ /dashboard/root/search-and-ban 3.28 kB 754 kB
├ ƒ /dashboard/root/unhost-accounts 5.7 kB 679 kB
├ ƒ /e2c 7.5 kB 529 kB
├ ƒ /embed/contribution-flow 2.33 kB 816 kB
├ ƒ /expense 6.38 kB 1.05 MB
├ ƒ /expenses 4.75 kB 1.07 MB
├ ƒ /external-redirect 3.67 kB 557 kB
├ ƒ /fiscal-hosting 10 kB 532 kB
├ ƒ /guest-join 5.82 kB 523 kB
├ ƒ /help-and-support 22 kB 721 kB
├ ƒ /home 216 B 538 kB
├ ƒ /how-it-works 6.07 kB 528 kB
├ ƒ /manage-contributions 8.15 kB 901 kB
├ ƒ /marketingPage 81.3 kB 592 kB
├ ƒ /member-invitations 6.37 kB 593 kB
├ ƒ /oauth/authorize 6.62 kB 581 kB
├ ƒ /order 16 kB 881 kB
├ ƒ /orders 14.9 kB 889 kB
├ ƒ /osc-host-application 31.5 kB 696 kB
├ ƒ /preview/[accountSlug]/[[...path]] 364 B 756 kB
├ ƒ /preview/[accountSlug]/support/[[...path]] 384 B 756 kB
├ ƒ /pricing 10.5 kB 527 kB
├ ƒ /redeem 23.6 kB 672 kB
├ ƒ /redeemed 4.51 kB 580 kB
├ ƒ /reset-password 8.78 kB 513 kB
├ ƒ /reset-password-completed 2.67 kB 520 kB
├ ƒ /reset-password-sent 3.12 kB 556 kB
├ ƒ /search 17.7 kB 589 kB
├ ƒ /signin 3.87 kB 554 kB
├ ƒ /signinLinkSent 3.21 kB 556 kB
├ ƒ /staticPage 28.1 kB 545 kB
├ ƒ /submitted-expenses 3.34 kB 1.07 MB
├ ƒ /terms-of-fiscal-sponsorship 742 B 441 kB
├ ƒ /tier 11 kB 887 kB
├ ƒ /transactions 17.9 kB 885 kB
├ ƒ /unsubscribeEmail 2.87 kB 520 kB
├ ƒ /update 10.3 kB 956 kB
├ ƒ /updatePaymentMethod 10.6 kB 574 kB
├ ƒ /updates 16.3 kB 874 kB
└ ƒ /welcome 4.96 kB 569 kB
├ chunks/appCommon-b8bd914fb84b2229.js 285 kB
├ chunks/framework-91261ea7164be8bd.js 66.8 kB
├ chunks/main-1a3c32dd0473688b.js 36.9 kB
├ chunks/pages/_app-1fc7bdfca80c7ec1.js 49 kB
├ css/720497e76efea6ff.css 18.8 kB
└ other shared chunks (total) 9.56 kB
ƒ Middleware 51.8 kB
ƒ (Dynamic) server-rendered on demand