299 lines
7.0 KiB
JavaScript
299 lines
7.0 KiB
JavaScript
import LeadsIcon from '@/components/Icons/LeadsIcon.vue'
|
|
import InviteIcon from '@/components/Icons/InviteIcon.vue'
|
|
import ConvertIcon from '@/components/Icons/ConvertIcon.vue'
|
|
import NoteIcon from '@/components/Icons/NoteIcon.vue'
|
|
import CommentIcon from '@/components/Icons/CommentIcon.vue'
|
|
import EmailIcon from '@/components/Icons/EmailIcon.vue'
|
|
import TaskIcon from '@/components/Icons/TaskIcon.vue'
|
|
import StepsIcon from '@/components/Icons/StepsIcon.vue'
|
|
import { capture } from '@/telemetry'
|
|
import { showSettings, activeSettingsPage } from '@/composables/settings'
|
|
import { useStorage } from '@vueuse/core'
|
|
import { call } from 'frappe-ui'
|
|
import { useRouter } from 'vue-router'
|
|
import { ref, reactive, computed, markRaw } from 'vue'
|
|
|
|
let router
|
|
|
|
export const minimize = ref(false)
|
|
|
|
export const isOnboardingStepsCompleted = useStorage(
|
|
'isOnboardingStepsCompleted',
|
|
false,
|
|
)
|
|
|
|
const firstLead = ref('')
|
|
const firstDeal = ref('')
|
|
|
|
const steps = reactive([
|
|
{
|
|
name: 'create_first_lead',
|
|
title: 'Create your first lead',
|
|
icon: markRaw(LeadsIcon),
|
|
completed: false,
|
|
onClick: () => {
|
|
minimize.value = true
|
|
router.push({ name: 'Leads' })
|
|
},
|
|
},
|
|
{
|
|
name: 'invite_your_team',
|
|
title: 'Invite your team',
|
|
icon: markRaw(InviteIcon),
|
|
completed: false,
|
|
onClick: () => {
|
|
minimize.value = true
|
|
showSettings.value = true
|
|
activeSettingsPage.value = 'Invite Members'
|
|
},
|
|
},
|
|
{
|
|
name: 'convert_lead_to_deal',
|
|
title: 'Convert lead to deal',
|
|
icon: markRaw(ConvertIcon),
|
|
completed: false,
|
|
onClick: async () => {
|
|
minimize.value = true
|
|
|
|
let lead = await getFirstLead()
|
|
|
|
if (lead) {
|
|
router.push({ name: 'Lead', params: { leadId: lead } })
|
|
} else {
|
|
router.push({ name: 'Leads' })
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: 'create_first_task',
|
|
title: 'Create your first task',
|
|
icon: markRaw(TaskIcon),
|
|
completed: false,
|
|
onClick: async () => {
|
|
minimize.value = true
|
|
let deal = await getFirstDeal()
|
|
|
|
if (deal) {
|
|
router.push({
|
|
name: 'Deal',
|
|
params: { dealId: deal },
|
|
hash: '#tasks',
|
|
})
|
|
} else {
|
|
router.push({ name: 'Tasks' })
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: 'create_first_note',
|
|
title: 'Create your first note',
|
|
icon: markRaw(NoteIcon),
|
|
completed: false,
|
|
onClick: async () => {
|
|
minimize.value = true
|
|
let deal = await getFirstDeal()
|
|
|
|
if (deal) {
|
|
router.push({
|
|
name: 'Deal',
|
|
params: { dealId: deal },
|
|
hash: '#notes',
|
|
})
|
|
} else {
|
|
router.push({ name: 'Notes' })
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: 'add_first_comment',
|
|
title: 'Add your first comment',
|
|
icon: markRaw(CommentIcon),
|
|
completed: false,
|
|
onClick: async () => {
|
|
minimize.value = true
|
|
let deal = await getFirstDeal()
|
|
|
|
if (deal) {
|
|
router.push({
|
|
name: 'Deal',
|
|
params: { dealId: deal },
|
|
hash: '#comments',
|
|
})
|
|
} else {
|
|
router.push({ name: 'Leads' })
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: 'send_first_email',
|
|
title: 'Send email',
|
|
icon: markRaw(EmailIcon),
|
|
completed: false,
|
|
onClick: async () => {
|
|
minimize.value = true
|
|
let deal = await getFirstDeal()
|
|
|
|
if (deal) {
|
|
router.push({
|
|
name: 'Deal',
|
|
params: { dealId: deal },
|
|
hash: '#emails',
|
|
})
|
|
} else {
|
|
router.push({ name: 'Leads' })
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: 'change_deal_status',
|
|
title: 'Change deal status',
|
|
icon: markRaw(StepsIcon),
|
|
completed: false,
|
|
onClick: async () => {
|
|
minimize.value = true
|
|
let deal = await getFirstDeal()
|
|
|
|
if (deal) {
|
|
router.push({
|
|
name: 'Deal',
|
|
params: { dealId: deal },
|
|
hash: '#activity',
|
|
})
|
|
} else {
|
|
router.push({ name: 'Leads' })
|
|
}
|
|
},
|
|
},
|
|
])
|
|
|
|
async function getFirstLead() {
|
|
if (firstLead.value) return firstLead.value
|
|
return await call('crm.api.onboarding.get_first_lead')
|
|
}
|
|
|
|
async function getFirstDeal() {
|
|
if (firstDeal.value) return firstDeal.value
|
|
return await call('crm.api.onboarding.get_first_deal')
|
|
}
|
|
|
|
const stepsCompleted = computed(
|
|
() => steps.filter((step) => step.completed).length,
|
|
)
|
|
const totalSteps = ref(steps.length)
|
|
|
|
const completedPercentage = computed(() =>
|
|
Math.floor((stepsCompleted.value / totalSteps.value) * 100),
|
|
)
|
|
|
|
export function useOnboarding() {
|
|
router = useRouter()
|
|
|
|
syncStatus()
|
|
|
|
function skip(step) {
|
|
updateOnboardingStep(step, true)
|
|
}
|
|
|
|
function skipAll() {
|
|
updateAll(true)
|
|
}
|
|
|
|
function reset() {
|
|
updateAll(false, true)
|
|
}
|
|
|
|
function updateOnboardingStep(step, skipped = false) {
|
|
if (isOnboardingStepsCompleted.value) return
|
|
let user = window.user
|
|
if (!user) return false
|
|
|
|
if (!user.onboarding_status['frappe_crm_onboarding_status']) {
|
|
user.onboarding_status['frappe_crm_onboarding_status'] = steps.map(
|
|
(s) => {
|
|
return { name: s.name, completed: false }
|
|
},
|
|
)
|
|
}
|
|
|
|
let _steps = user.onboarding_status['frappe_crm_onboarding_status']
|
|
let index = _steps.findIndex((s) => s.name === step)
|
|
if (index !== -1) {
|
|
_steps[index].completed = true
|
|
steps[index].completed = true
|
|
}
|
|
|
|
window.user = user
|
|
|
|
if (skipped) {
|
|
capture('onboarding_skipped_' + step)
|
|
} else {
|
|
capture('onboarding_' + step)
|
|
}
|
|
|
|
call('crm.api.onboarding.update_user_onboarding_status', {
|
|
steps: JSON.stringify(_steps),
|
|
})
|
|
}
|
|
|
|
function updateAll(value, reset = false) {
|
|
if (isOnboardingStepsCompleted.value && !reset) return
|
|
let user = window.user
|
|
if (!user) return false
|
|
|
|
let _steps
|
|
|
|
if (!user.onboarding_status['frappe_crm_onboarding_status']) {
|
|
user.onboarding_status['frappe_crm_onboarding_status'] = steps.map(
|
|
(s) => {
|
|
return { name: s.name, completed: value }
|
|
},
|
|
)
|
|
} else {
|
|
_steps = user.onboarding_status['frappe_crm_onboarding_status']
|
|
_steps.forEach((step) => {
|
|
step.completed = value
|
|
})
|
|
}
|
|
|
|
steps.forEach((step) => {
|
|
step.completed = value
|
|
})
|
|
|
|
window.user = user
|
|
|
|
capture(value ? 'onboarding_skipped_all' : 'onboarding_reset_steps')
|
|
|
|
call('crm.api.onboarding.update_user_onboarding_status', {
|
|
steps: JSON.stringify(_steps),
|
|
})
|
|
}
|
|
|
|
function syncStatus() {
|
|
if (isOnboardingStepsCompleted.value) return
|
|
let user = window.user
|
|
if (!user) return false
|
|
|
|
if (user.onboarding_status['frappe_crm_onboarding_status']) {
|
|
let _steps = user.onboarding_status['frappe_crm_onboarding_status']
|
|
_steps.forEach((step, index) => {
|
|
steps[index].completed = step.completed
|
|
})
|
|
isOnboardingStepsCompleted.value = _steps.every((step) => step.completed)
|
|
} else {
|
|
isOnboardingStepsCompleted.value = false
|
|
}
|
|
}
|
|
|
|
return {
|
|
steps,
|
|
stepsCompleted,
|
|
totalSteps,
|
|
completedPercentage,
|
|
updateOnboardingStep,
|
|
skip,
|
|
skipAll,
|
|
reset,
|
|
syncStatus,
|
|
}
|
|
}
|