diff --git a/src/components/TimelineOnboarding.vue b/src/components/TimelineOnboarding.vue
new file mode 100644
index 00000000000..bc5feb93a71
--- /dev/null
+++ b/src/components/TimelineOnboarding.vue
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+ {{ t('onboarding.title') }}
+
+
{{ t('onboarding.subtitle') }}
+
+
+
+
+
+
+
+
+
+ -
+
+ {{ checkListItem.name }}
+
+
+
+
+
đ {{ t('onboarding.congratulations') }}
+
+
+
+
+
+
diff --git a/src/composables/useOnboardingChecklist.ts b/src/composables/useOnboardingChecklist.ts
new file mode 100644
index 00000000000..e7031f73310
--- /dev/null
+++ b/src/composables/useOnboardingChecklist.ts
@@ -0,0 +1,85 @@
+import { computed, ref, watch } from 'vue';
+import { useProfiles } from '@/composables/useProfiles';
+import { useWeb3 } from '@/composables/useWeb3';
+import { useI18n } from '@/composables/useI18n';
+import { useApolloQuery } from '@/composables/useApolloQuery';
+import { PROPOSALS_QUERY } from '@/helpers/queries';
+import { ACTIVITY_VOTES_QUERY } from '@/helpers/queries';
+import { useFollowSpace } from '@/composables/useFollowSpace';
+
+const { t } = useI18n();
+
+const { apolloQuery } = useApolloQuery();
+const { profiles } = useProfiles();
+const { web3Account } = useWeb3();
+const { followingSpaces } = useFollowSpace();
+
+const profile = computed(() => profiles.value[web3Account.value]);
+
+const hasSetPublicProfile = computed(() =>
+ profile.value?.name ? true : false
+);
+const hasFollowedSpace = computed(() => followingSpaces.value.length);
+const hasVoted = ref(false);
+const hasCreatedProposal = ref(false);
+
+const onboardingChecklist = ref([
+ {
+ checked: hasSetPublicProfile,
+ name: t('onboarding.profile')
+ },
+ {
+ checked: hasFollowedSpace,
+ name: t('onboarding.space')
+ },
+ {
+ checked: hasVoted,
+ name: t('onboarding.vote')
+ },
+ {
+ checked: hasCreatedProposal,
+ name: t('onboarding.proposal')
+ }
+]);
+
+async function loadVotes() {
+ const votes = await apolloQuery(
+ {
+ query: ACTIVITY_VOTES_QUERY,
+ variables: {
+ voter: profile.value.id
+ }
+ },
+ 'votes'
+ );
+
+ hasVoted.value = votes.length ? true : false;
+}
+
+async function loadProposals() {
+ const proposals = await apolloQuery(
+ {
+ query: PROPOSALS_QUERY,
+ variables: {
+ first: 1,
+ skip: 0,
+ state: 'all',
+ author_in: [profile.value.id]
+ }
+ },
+ 'proposals'
+ );
+
+ hasCreatedProposal.value = proposals.length ? true : false;
+}
+
+watch(profiles, p => {
+ if (profile.value) {
+ loadVotes();
+ loadProposals();
+ }
+});
+
+export function useOnboardingChecklist() {
+ return { onboardingChecklist };
+}
diff --git a/src/locales/default.json b/src/locales/default.json
index a545d6e41a6..11de4983bc0 100644
--- a/src/locales/default.json
+++ b/src/locales/default.json
@@ -612,5 +612,14 @@
"empty": "There are no assets in this contract"
},
"24hChange": "24h change"
+ },
+ "onboarding": {
+ "title": "New to Snapshot?",
+ "subtitle": "Here is a quick check list to get started:",
+ "profile": "Set your public profile",
+ "space": "Join your favorite space",
+ "vote": "Cast your first vote",
+ "proposal": "Create a proposal",
+ "congratulations": "Congratulations"
}
}
diff --git a/src/locales/fr-FR.json b/src/locales/fr-FR.json
index 39cd31cd132..56fe5ef115d 100644
--- a/src/locales/fr-FR.json
+++ b/src/locales/fr-FR.json
@@ -602,5 +602,14 @@
"empty": "There are no assets in this contract"
},
"24hChange": "24h change"
+ },
+ "onboarding": {
+ "title": "Nouveau sur Snapshot ?",
+ "subtitle": "Voici une checklist rapide pour commencer :",
+ "profile": "DĂ©finir votre profil public",
+ "space": "Rejoindre votre espace préféré",
+ "vote": "Votre premier vote",
+ "proposal": "Créer une proposition",
+ "congratulations": "FĂ©licitations"
}
}
diff --git a/src/views/TimelineView.vue b/src/views/TimelineView.vue
index 5107b685365..b574ebc16be 100644
--- a/src/views/TimelineView.vue
+++ b/src/views/TimelineView.vue
@@ -176,6 +176,13 @@ function selectState(e) {
+
+
+