Skip to content

Commit ef68d72

Browse files
feat(APP-560): Add onboarding dashboard state for admin-only DAOs (#1061)
* Implementation draft Signed-off-by: Milos Dzepina <milos@aragon.org> * Update card styles Signed-off-by: Milos Dzepina <milos@aragon.org> * migrate to object illustration Signed-off-by: Milos Dzepina <milos@aragon.org> * Use classnames Signed-off-by: Milos Dzepina <milos@aragon.org> * Implement mobile view Signed-off-by: Milos Dzepina <milos@aragon.org> * Create shared CtaCard component Signed-off-by: Milos Dzepina <milos@aragon.org> * Align gaps with design Signed-off-by: Milos Dzepina <milos@aragon.org> * Extract DashboardOnboarded component Signed-off-by: Milos Dzepina <milos@aragon.org> * Extract sub-components Signed-off-by: Milos Dzepina <milos@aragon.org> * Update NonAdminOnboarding Signed-off-by: Milos Dzepina <milos@aragon.org> * UPdate tests Signed-off-by: Milos Dzepina <milos@aragon.org> * Fix page inter-load states Signed-off-by: Milos Dzepina <milos@aragon.org> * Fix type issues Signed-off-by: Milos Dzepina <milos@aragon.org> * Fix tests Signed-off-by: Milos Dzepina <milos@aragon.org> * Address review comments Signed-off-by: Milos Dzepina <milos@aragon.org> * Migrate to useSelectedLayoutSegment Signed-off-by: Milos Dzepina <milos@aragon.org> * Refactor CtaCard props Signed-off-by: Milos Dzepina <milos@aragon.org> * Remove unused file Signed-off-by: Milos Dzepina <milos@aragon.org> * Fix type issue Signed-off-by: Milos Dzepina <milos@aragon.org> * Revise onboarding messages for clarity and context Updated descriptions and titles for governance onboarding messages. Signed-off-by: Evan Aronson <93671071+evanaronson@users.noreply.github.com> * Add daoName translation param Signed-off-by: Milos Dzepina <milos@aragon.org> * Update heading size Signed-off-by: Milos Dzepina <milos@aragon.org> * Apply review comments Signed-off-by: Milos Dzepina <milos@aragon.org> * Fix not-connected case Signed-off-by: Milos Dzepina <milos@aragon.org> --------- Signed-off-by: Milos Dzepina <milos@aragon.org> Signed-off-by: Evan Aronson <93671071+evanaronson@users.noreply.github.com> Co-authored-by: Evan Aronson <93671071+evanaronson@users.noreply.github.com>
1 parent 3a09a99 commit ef68d72

File tree

22 files changed

+789
-293
lines changed

22 files changed

+789
-293
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@aragon/app": minor
3+
---
4+
5+
Add onboarding dashboard state with CTAs when only the admin plugin is installed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@
113113
"engines": {
114114
"node": ">=24.13.0"
115115
},
116-
"packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be",
116+
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319",
117117
"pnpm": {
118118
"overrides": {
119119
"isomorphic-dompurify>jsdom": "26.1.0",

src/assets/images/doItYourselfIcon.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/assets/images/enterpriseServiceIcon.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/assets/images/noCodeSetup.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/assets/locales/en.json

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,6 @@
294294
"bannerDao": {
295295
"adminMember": {
296296
"action": "Add governance",
297-
"manage": "Manage admins",
298297
"message": "You are a DAO admin. You can add as many custom governance processes as your DAO needs."
299298
},
300299
"adminPlugin": {
@@ -1308,6 +1307,32 @@
13081307
"proposals": "Proposals",
13091308
"treasury": "Treasury"
13101309
}
1310+
},
1311+
"dashboardOnboarding": {
1312+
"admin": {
1313+
"description": "Your organization has no governance yet. Without it, only you can execute actions - your team or community can't participate. Choose how you want to get set up.",
1314+
"divider": "or",
1315+
"enterprise": {
1316+
"action": "Get in touch",
1317+
"description": "Most successful organizations on Aragon are launched with expert guidance. Work with our team to design and deploy a governance and tokenomics setup tailored to your organization.",
1318+
"tag": "Best for custom setups",
1319+
"title": "Work with the Aragon team"
1320+
},
1321+
"free": {
1322+
"addGovernance": "Add governance",
1323+
"description": "Use the no-code wizard to deploy governance and configure your organization's governance or explore our documentation to build it yourself.",
1324+
"title": "Set up governance yourself",
1325+
"viewDocs": "View docs"
1326+
},
1327+
"subtitle": "Now, let's get started!",
1328+
"welcome": "Welcome"
1329+
},
1330+
"nonAdmin": {
1331+
"description": "Admins can install plugins that enable governance, affect tokenomics, or support other onchain operations.",
1332+
"title": "{{daoName}} is being set up",
1333+
"viewAdmins": "View admins",
1334+
"welcome": "Welcome"
1335+
}
13111336
}
13121337
},
13131338
"explore": {
@@ -1339,6 +1364,7 @@
13391364
"enterpriseService": {
13401365
"actionLabel": "Get in touch",
13411366
"subtitle": "Let Aragon design and build custom governance and tokenomics mechanisms for your organization.",
1367+
"tag": "Recommended",
13421368
"title": "Work with our team"
13431369
},
13441370
"hero": {

src/modules/application/components/bannerDao/bannerDao.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

33
import { Button, IconType, invariant } from '@aragon/gov-ui-kit';
4+
import { useSelectedLayoutSegment } from 'next/navigation';
45
import type { Hex } from 'viem';
56
import { CreateDaoDialogId } from '@/modules/createDao/constants/createDaoDialogId';
67
import type { ICreateProcessDetailsDialogParams } from '@/modules/createDao/dialogs/createProcessDetailsDialog';
@@ -26,6 +27,7 @@ export const BannerDao: React.FC<IBannerDaoProps> = (props) => {
2627
const { t } = useTranslations();
2728
const { open } = useDialogContext();
2829
const { isEnabled } = useFeatureFlags();
30+
const segment = useSelectedLayoutSegment();
2931

3032
const { isAdminMember, adminPlugin } = useAdminStatus({
3133
daoId: dao.id,
@@ -43,6 +45,8 @@ export const BannerDao: React.FC<IBannerDaoProps> = (props) => {
4345
open(CreateDaoDialogId.CREATE_PROCESS_DETAILS, { params });
4446
};
4547

48+
const isSettingsPage = segment === 'settings';
49+
4650
const displayAdminMemberBanner =
4751
isAdminMember && isEnabled('governanceDesigner');
4852

@@ -52,7 +56,7 @@ export const BannerDao: React.FC<IBannerDaoProps> = (props) => {
5256
? 'adminPlugin'
5357
: null;
5458

55-
if (bannerType == null) {
59+
if (bannerType == null || !isSettingsPage) {
5660
return null;
5761
}
5862

@@ -79,15 +83,6 @@ export const BannerDao: React.FC<IBannerDaoProps> = (props) => {
7983
{t('app.application.bannerDao.adminPlugin.action')}
8084
</Button>
8185
)}
82-
{isAdminMember && (
83-
<Button
84-
href={`${daoUrl}/settings`}
85-
size="sm"
86-
variant="tertiary"
87-
>
88-
{t('app.application.bannerDao.adminMember.manage')}
89-
</Button>
90-
)}
9186
</div>
9287
</Banner>
9388
);
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
'use client';
2+
3+
import { Button, IconType } from '@aragon/gov-ui-kit';
4+
import { AssetList } from '@/modules/finance/components/assetList';
5+
import { DaoMemberList } from '@/modules/governance/components/daoMemberList';
6+
import { DaoProposalList } from '@/modules/governance/components/daoProposalList';
7+
import { daoMembersPageFilterParam } from '@/modules/governance/pages/daoMembersPage';
8+
import { daoProposalsPageFilterParam } from '@/modules/governance/pages/daoProposalsPage';
9+
import type { IDao } from '@/shared/api/daoService';
10+
import { Page } from '@/shared/components/page';
11+
import { useTranslations } from '@/shared/components/translationsProvider';
12+
import { useDaoPluginFilterUrlParam } from '@/shared/hooks/useDaoPluginFilterUrlParam';
13+
import { PluginType } from '@/shared/types';
14+
import { daoUtils } from '@/shared/utils/daoUtils';
15+
import {
16+
daoDashboardPageMembersFilterParam,
17+
daoDashboardPageProposalsFilterParam,
18+
} from '../../pages/daoDashboardPage';
19+
20+
const dashboardProposalsCount = 3;
21+
const dashboardMembersCount = 6;
22+
const dashboardAssetsCount = 3;
23+
24+
export interface IDashboardOnboardedProps {
25+
/**
26+
* The DAO data.
27+
*/
28+
dao: IDao;
29+
}
30+
31+
export const DashboardOnboarded: React.FC<IDashboardOnboardedProps> = (
32+
props,
33+
) => {
34+
const { dao } = props;
35+
36+
const { t } = useTranslations();
37+
38+
const { activePlugin: membersPlugin, setActivePlugin: setMembersPlugin } =
39+
useDaoPluginFilterUrlParam({
40+
daoId: dao.id,
41+
type: PluginType.BODY,
42+
includeSubPlugins: true,
43+
includeLinkedAccounts: true,
44+
name: daoDashboardPageMembersFilterParam,
45+
});
46+
47+
const {
48+
activePlugin: proposalsPlugin,
49+
setActivePlugin: setProposalsPlugin,
50+
} = useDaoPluginFilterUrlParam({
51+
daoId: dao.id,
52+
type: PluginType.PROCESS,
53+
includeGroupFilter: true,
54+
includeLinkedAccounts: true,
55+
name: daoDashboardPageProposalsFilterParam,
56+
});
57+
58+
const daoUrl = daoUtils.getDaoUrl(dao)!;
59+
const hasSupportedPlugins = daoUtils.hasSupportedPlugins(dao);
60+
61+
const proposalListParams = {
62+
queryParams: {
63+
daoId: dao.id,
64+
pageSize: dashboardProposalsCount,
65+
sort: 'blockTimestamp',
66+
isSubProposal: false,
67+
},
68+
};
69+
const memberListParams = {
70+
queryParams: { daoId: dao.id, pageSize: dashboardMembersCount },
71+
};
72+
const assetListParams = {
73+
queryParams: { daoId: dao.id, pageSize: dashboardAssetsCount },
74+
};
75+
76+
const membersPageUrl = `${daoUrl}/members?${daoMembersPageFilterParam}=${membersPlugin?.uniqueId ?? ''}`;
77+
const proposalsPageUrl = `${daoUrl}/proposals?${daoProposalsPageFilterParam}=${proposalsPlugin?.uniqueId ?? ''}`;
78+
79+
return (
80+
<>
81+
{hasSupportedPlugins && (
82+
<Page.MainSection
83+
title={t(
84+
'app.dashboard.daoDashboardPage.main.proposals.title',
85+
)}
86+
>
87+
<DaoProposalList
88+
hidePagination={true}
89+
initialParams={proposalListParams}
90+
onValueChange={setProposalsPlugin}
91+
value={proposalsPlugin}
92+
>
93+
<Button
94+
className="self-start"
95+
href={proposalsPageUrl}
96+
iconRight={IconType.CHEVRON_RIGHT}
97+
size="md"
98+
variant="tertiary"
99+
>
100+
{t('app.dashboard.daoDashboardPage.main.viewAll')}
101+
</Button>
102+
</DaoProposalList>
103+
</Page.MainSection>
104+
)}
105+
{hasSupportedPlugins && (
106+
<Page.MainSection
107+
title={t(
108+
'app.dashboard.daoDashboardPage.main.members.title',
109+
)}
110+
>
111+
<DaoMemberList.Container
112+
hidePagination={true}
113+
initialParams={memberListParams}
114+
onValueChange={setMembersPlugin}
115+
value={membersPlugin}
116+
>
117+
<Button
118+
className="self-start"
119+
href={membersPageUrl}
120+
iconRight={IconType.CHEVRON_RIGHT}
121+
size="md"
122+
variant="tertiary"
123+
>
124+
{t('app.dashboard.daoDashboardPage.main.viewAll')}
125+
</Button>
126+
</DaoMemberList.Container>
127+
</Page.MainSection>
128+
)}
129+
<Page.MainSection
130+
title={t('app.dashboard.daoDashboardPage.main.assets.title')}
131+
>
132+
<AssetList.Default
133+
hidePagination={true}
134+
initialParams={assetListParams}
135+
>
136+
<Button
137+
className="self-start"
138+
href={`${daoUrl}/assets`}
139+
iconRight={IconType.CHEVRON_RIGHT}
140+
size="md"
141+
variant="tertiary"
142+
>
143+
{t('app.dashboard.daoDashboardPage.main.viewAll')}
144+
</Button>
145+
</AssetList.Default>
146+
</Page.MainSection>
147+
</>
148+
);
149+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export type { IDashboardOnboardedProps } from './dashboardOnboarded';
2+
export { DashboardOnboarded } from './dashboardOnboarded';
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
'use client';
2+
3+
import { Heading } from '@aragon/gov-ui-kit';
4+
import { CtaCard } from '@/shared/components/ctaCard';
5+
import { useTranslations } from '@/shared/components/translationsProvider';
6+
7+
export interface IAdminOnboardingProps {
8+
/**
9+
* Display name of the connected user (ENS or truncated address).
10+
*/
11+
displayName?: string;
12+
/**
13+
* Callback to open the governance designer dialog.
14+
*/
15+
onAddGovernance: () => void;
16+
}
17+
18+
export const AdminOnboarding: React.FC<IAdminOnboardingProps> = (props) => {
19+
const { displayName, onAddGovernance } = props;
20+
21+
const { t } = useTranslations();
22+
23+
return (
24+
<div className="flex flex-col gap-8">
25+
<div className="flex flex-col gap-4">
26+
<Heading className="text-3xl! md:text-4xl!" size="h1">
27+
{t('app.dashboard.dashboardOnboarding.admin.welcome')}{' '}
28+
{displayName != null && (
29+
<span className="text-primary-400">{displayName}</span>
30+
)}
31+
<br />
32+
{t('app.dashboard.dashboardOnboarding.admin.subtitle')}
33+
</Heading>
34+
<p className="text-base text-neutral-500 md:text-lg">
35+
{t('app.dashboard.dashboardOnboarding.admin.description')}
36+
</p>
37+
</div>
38+
<div className="flex flex-col gap-6">
39+
<CtaCard
40+
description={t(
41+
'app.dashboard.dashboardOnboarding.admin.enterprise.description',
42+
)}
43+
isPrimary={true}
44+
objectType="USERS"
45+
primaryAction={{
46+
href: 'https://www.aragon.org/get-assistance-form',
47+
label: t(
48+
'app.dashboard.dashboardOnboarding.admin.enterprise.action',
49+
),
50+
}}
51+
tag={t(
52+
'app.dashboard.dashboardOnboarding.admin.enterprise.tag',
53+
)}
54+
title={t(
55+
'app.dashboard.dashboardOnboarding.admin.enterprise.title',
56+
)}
57+
/>
58+
<div className="flex items-center gap-4">
59+
<div className="h-px flex-1 bg-neutral-100" />
60+
<span className="text-neutral-300 text-sm">
61+
{t('app.dashboard.dashboardOnboarding.admin.divider')}
62+
</span>
63+
<div className="h-px flex-1 bg-neutral-100" />
64+
</div>
65+
<CtaCard
66+
description={t(
67+
'app.dashboard.dashboardOnboarding.admin.free.description',
68+
)}
69+
isPrimary={false}
70+
objectType="SMART_CONTRACT"
71+
primaryAction={{
72+
label: t(
73+
'app.dashboard.dashboardOnboarding.admin.free.addGovernance',
74+
),
75+
onClick: onAddGovernance,
76+
}}
77+
secondaryAction={{
78+
label: t(
79+
'app.dashboard.dashboardOnboarding.admin.free.viewDocs',
80+
),
81+
href: 'https://docs.aragon.org',
82+
}}
83+
title={t(
84+
'app.dashboard.dashboardOnboarding.admin.free.title',
85+
)}
86+
/>
87+
</div>
88+
</div>
89+
);
90+
};

0 commit comments

Comments
 (0)