Skip to content
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

feat(): Onboarding Checklist #2863

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions src/components/TimelineOnboarding.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { useI18n } from '@/composables/useI18n';
import { useOnboardingChecklist } from '@/composables/useOnboardingChecklist';
import { lsSet, lsGet } from '@/helpers/utils';

const { t } = useI18n();

const { onboardingChecklist } = useOnboardingChecklist();

const showOnboarding = ref(true);

const checkListCompleted = computed(() => {
let completed = true;

onboardingChecklist.value.forEach(checkListItem => {
if (!checkListItem.checked) {
completed = false;
return;
}
});

return completed;
});

if (lsGet('timelineOnboarding') == 'hidden') {
showOnboarding.value = false;
}

watch(checkListCompleted, completed => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of auto hiding it on completion we could have a share on twitter button

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could be a good idea. I think it should be also discussed with @bonustrack.

It will ask some UX thinking about how to handle the closing of this panel.

if (completed) lsSet('timelineOnboarding', 'hidden');
samuveth marked this conversation as resolved.
Show resolved Hide resolved
});

function closeOnboarding() {
lsSet('timelineOnboarding', 'hidden');
showOnboarding.value = false;
}
</script>

<template>
<transition name="fade">
<div
v-if="showOnboarding"
class="border-skin-border bg-skin-block-bg text-white md:rounded-lg md:border"
>
<div class="p-4">
<div class="flex">
<div class="flex-grow">
<h3 class="text-bold">{{ t('onboarding.title') }}</h3>
<p>{{ t('onboarding.subtitle') }}</p>
</div>
<div class="mt-2">
<button
class="opacity-50 transition-opacity hover:opacity-100"
:aria-label="t('onboarding.close')"
@click="closeOnboarding"
>
<svg class="h-[24px] w-[24px]" fill="none" viewBox="0 0 12 12">
<path
d="M4 8l2-2m0 0l2-2M6 6L4 4m2 2l2 2"
stroke="currentColor"
stroke-width="1"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
samuveth marked this conversation as resolved.
Show resolved Hide resolved
</div>
</div>

<ul class="mt-4 flex-col space-y-2">
<li
v-for="checkListItem in onboardingChecklist"
:key="checkListItem.name"
class="flex items-center"
>
<div class="w-4">
<i-ho-check
v-if="checkListItem.checked"
class="text-[17px] text-green"
/>
<div v-else class="h-3 w-3 border"></div>
</div>
{{ checkListItem.name }}
</li>
</ul>
<transition name="fade">
<div v-if="checkListCompleted" class="mt-4">
<h3>🎉 {{ t('onboarding.congratulations') }}</h3>
</div>
</transition>
</div>
</div>
</transition>
</template>
85 changes: 85 additions & 0 deletions src/composables/useOnboardingChecklist.ts
Original file line number Diff line number Diff line change
@@ -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([
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be hard for new users figuring out how to complete each list item. Maybe each item should be collapsable with additional links and information. @ManuBernard do you have a designer with who we could try some things out?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have followed the design provided by @bonustrack :
https://www.figma.com/file/GS2AS8G3YCYjeH1dFTFpIn/Snapshot---onboarding-section?node-id=0%3A1

Not sure how to move forward, maybe you should talk together and see if we want to improve this in this PR or create a new one later?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see. Yeah I wasn't aware of this design sorry for the confusion :)

{
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 };
}
10 changes: 10 additions & 0 deletions src/locales/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -612,5 +612,15 @@
"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:",
"close": "Hide onboarding cheklist",
"profile": "Set your public profile",
"space": "Join your favorite space",
"vote": "Cast your first vote",
"proposal": "Create a proposal",
"congratulations": "Congratulations"
}
}
10 changes: 10 additions & 0 deletions src/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -602,5 +602,15 @@
"empty": "There are no assets in this contract"
},
"24hChange": "24h change"
},
"onboarding": {
"title": "Nouveau sur Snapshot ?",
"subtitle": "Voici une checklist rapide pour commencer :",
"close": "Cacher la checklist",
"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"
}
}
3 changes: 3 additions & 0 deletions src/views/TimelineView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ function selectState(e) {
</template>
</BaseDropdown>
</div>

<TimelineOnboarding class="mb-4" />

<div class="border-skin-border bg-skin-block-bg md:rounded-lg md:border">
<LoadingRow
v-if="
Expand Down