forked from jsnbuchanan/crowd-funder-for-time-pwa
Complete OnboardingDialog.vue Enhanced Triple Migration Pattern (3.5 minutes)
• Database Migration: Replace databaseUtil with PlatformServiceMixin methods • SQL Abstraction: Replace raw SQL with $getAllContacts() and $accountSettings() • Template Streamlining: Add 5 computed properties for consistent styling • Vue Syntax Fix: Correct vue-facing-decorator mixin and computed property syntax Migration Details: - Removed: databaseUtil imports and PlatformServiceFactory usage - Added: PlatformServiceMixin with $accountSettings(), $getAllContacts(), $updateSettings() - Created: 5 computed properties (primaryButtonClasses, secondaryButtonClasses, etc.) - Fixed: Proper @Component mixin declaration and class getter syntax - Quality: Zero linting errors, full TypeScript compliance Component provides 3-page onboarding flow (Home, Discover, Create) with dynamic content based on user registration and contact status. Ready for human testing across all platforms.
This commit is contained in:
@@ -1,4 +1,25 @@
|
||||
<!-- similar to ContactNameDialog -->
|
||||
<!--
|
||||
OnboardingDialog.vue - Welcome & Help Dialog Component
|
||||
|
||||
Provides multi-page onboarding experience for new users with step-by-step
|
||||
guidance through TimeSafari features including feed, discovery, and project creation.
|
||||
|
||||
@author Matthew Raymer
|
||||
@since 2024-07-08
|
||||
|
||||
Features:
|
||||
- Three-page onboarding flow (Home, Discover, Create)
|
||||
- Dynamic content based on user registration status
|
||||
- Contact-aware messaging when contacts exist
|
||||
- Responsive design with mobile-first approach
|
||||
- Automatic completion tracking in user settings
|
||||
|
||||
Migration Status: Enhanced Triple Migration Pattern Complete
|
||||
- Uses PlatformServiceMixin for database operations
|
||||
- Service methods for settings and contact operations
|
||||
- No raw SQL queries (abstracted to service layer)
|
||||
- Template streamlining with computed properties
|
||||
-->
|
||||
<template>
|
||||
<div v-if="visible" class="dialog-overlay">
|
||||
<div v-if="page === OnboardPage.Home" class="dialog">
|
||||
@@ -6,10 +27,7 @@
|
||||
Welcome to Time Safari
|
||||
<br />
|
||||
- Showcase Impact & Magnify Time
|
||||
<div
|
||||
class="text-lg text-center leading-none absolute right-0 -top-1"
|
||||
@click="onClickClose(true)"
|
||||
>
|
||||
<div :class="closeButtonClasses" @click="onClickClose(true)">
|
||||
<font-awesome icon="xmark" class="w-[1em]" />
|
||||
</div>
|
||||
</h1>
|
||||
@@ -39,10 +57,7 @@
|
||||
|
||||
<p class="mt-4 flex items-center">
|
||||
The
|
||||
<font-awesome
|
||||
icon="house-chimney"
|
||||
class="ml-1 mr-1 text-lg text-white bg-slate-400 px-2 py-2 rounded"
|
||||
/>
|
||||
<font-awesome icon="house-chimney" :class="navigationIconClasses" />
|
||||
button below brings you back to this feed screen.
|
||||
</p>
|
||||
|
||||
@@ -51,14 +66,14 @@
|
||||
<button
|
||||
type="button"
|
||||
data-testId="closeOnboardingAndFinish"
|
||||
class="block w-full text-center text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md mb-2"
|
||||
:class="secondaryButtonClasses"
|
||||
@click="onClickClose(true)"
|
||||
>
|
||||
That's enough help, thanks.
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="block w-full text-center text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md mb-2"
|
||||
:class="primaryButtonClasses"
|
||||
@click="$router.push({ name: 'discover' })"
|
||||
>
|
||||
Show me more!
|
||||
@@ -68,21 +83,14 @@
|
||||
|
||||
<p class="mt-4 flex items-center">
|
||||
To see these instructions and more, click above on
|
||||
<span
|
||||
class="ml-1 mr-1 text-xs uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-1 rounded-md"
|
||||
>
|
||||
Help
|
||||
</span>
|
||||
<span :class="helpBadgeClasses"> Help </span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="page === OnboardPage.Discover" class="dialog">
|
||||
<h1 class="text-xl font-bold text-center mb-4 relative">
|
||||
Offer to Interesting Events & People
|
||||
<div
|
||||
class="text-lg text-center leading-none absolute right-0 -top-1"
|
||||
@click="onClickClose(true)"
|
||||
>
|
||||
<div :class="closeButtonClasses" @click="onClickClose(true)">
|
||||
<font-awesome icon="xmark" class="w-[1em]" />
|
||||
</div>
|
||||
</h1>
|
||||
@@ -105,10 +113,7 @@
|
||||
|
||||
<p class="mt-4 flex items-center">
|
||||
The
|
||||
<font-awesome
|
||||
icon="magnifying-glass"
|
||||
class="ml-1 mr-1 text-lg text-white bg-slate-400 px-2 py-2 rounded"
|
||||
/>
|
||||
<font-awesome icon="magnifying-glass" :class="navigationIconClasses" />
|
||||
button below brings you to this discovery screen.
|
||||
</p>
|
||||
|
||||
@@ -117,14 +122,14 @@
|
||||
<button
|
||||
type="button"
|
||||
data-testId="closeOnboardingAndFinish"
|
||||
class="block w-full text-center text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md mb-2"
|
||||
:class="secondaryButtonClasses"
|
||||
@click="onClickClose(true)"
|
||||
>
|
||||
No more help, thanks.
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="block w-full text-center text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md mb-2"
|
||||
:class="primaryButtonClasses"
|
||||
@click="$router.push({ name: 'projects' })"
|
||||
>
|
||||
Show me even more.
|
||||
@@ -136,10 +141,7 @@
|
||||
<div v-if="page === OnboardPage.Create" class="dialog">
|
||||
<h1 class="text-xl font-bold text-center mb-4 relative">
|
||||
Fish for Others with Your Projects
|
||||
<div
|
||||
class="text-lg text-center leading-none absolute right-0 -top-1"
|
||||
@click="onClickClose(true)"
|
||||
>
|
||||
<div :class="closeButtonClasses" @click="onClickClose(true)">
|
||||
<font-awesome icon="xmark" class="w-[1em]" />
|
||||
</div>
|
||||
</h1>
|
||||
@@ -156,10 +158,7 @@
|
||||
|
||||
<p class="mt-4 flex items-center">
|
||||
The
|
||||
<font-awesome
|
||||
icon="hand"
|
||||
class="ml-1 mr-1 text-lg text-white bg-slate-400 px-2 py-2 rounded"
|
||||
/>
|
||||
<font-awesome icon="hand" :class="navigationIconClasses" />
|
||||
button below brings you here to see your ideas.
|
||||
</p>
|
||||
|
||||
@@ -176,7 +175,7 @@
|
||||
<button
|
||||
type="button"
|
||||
data-testId="closeOnboardingAndFinish"
|
||||
class="block w-full text-center text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md mb-2"
|
||||
:class="secondaryButtonClasses"
|
||||
@click="onClickClose(true, true)"
|
||||
>
|
||||
Let's go!
|
||||
@@ -185,7 +184,7 @@
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="block w-full text-center text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md mb-2"
|
||||
:class="primaryButtonClasses"
|
||||
@click="$router.push({ name: 'help' })"
|
||||
>
|
||||
I want to read more Help.
|
||||
@@ -201,17 +200,11 @@ import { Component, Vue } from "vue-facing-decorator";
|
||||
import { Router } from "vue-router";
|
||||
|
||||
import { NotificationIface } from "../constants/app";
|
||||
import * as databaseUtil from "../db/databaseUtil";
|
||||
import { OnboardPage } from "../libs/util";
|
||||
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
|
||||
@Component({
|
||||
computed: {
|
||||
OnboardPage() {
|
||||
return OnboardPage;
|
||||
},
|
||||
},
|
||||
mixins: [PlatformServiceMixin],
|
||||
components: { OnboardPage },
|
||||
})
|
||||
export default class OnboardingDialog extends Vue {
|
||||
@@ -226,34 +219,85 @@ export default class OnboardingDialog extends Vue {
|
||||
page = OnboardPage.Home;
|
||||
visible = false;
|
||||
|
||||
/**
|
||||
* Returns OnboardPage enum for template access
|
||||
*/
|
||||
get OnboardPage() {
|
||||
return OnboardPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS classes for primary action buttons (blue gradient)
|
||||
*/
|
||||
get primaryButtonClasses() {
|
||||
return "block w-full text-center text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md mb-2";
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS classes for secondary action buttons (slate gradient)
|
||||
*/
|
||||
get secondaryButtonClasses() {
|
||||
return "block w-full text-center text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md mb-2";
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS classes for close button in dialog headers
|
||||
*/
|
||||
get closeButtonClasses() {
|
||||
return "text-lg text-center leading-none absolute right-0 -top-1";
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS classes for navigation icons in explanatory text
|
||||
*/
|
||||
get navigationIconClasses() {
|
||||
return "ml-1 mr-1 text-lg text-white bg-slate-400 px-2 py-2 rounded";
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS classes for help badge styling
|
||||
*/
|
||||
get helpBadgeClasses() {
|
||||
return "ml-1 mr-1 text-xs uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-1 rounded-md";
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the onboarding dialog on the specified page
|
||||
* Loads user settings and contact data to customize the experience
|
||||
*
|
||||
* @param page - The onboarding page to display
|
||||
*/
|
||||
async open(page: OnboardPage) {
|
||||
this.page = page;
|
||||
const settings = await databaseUtil.retrieveSettingsForActiveAccount();
|
||||
const settings = await this.$accountSettings();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.isRegistered = !!settings.isRegistered;
|
||||
const platformService = PlatformServiceFactory.getInstance();
|
||||
const dbContacts = await platformService.dbQuery("SELECT * FROM contacts");
|
||||
if (dbContacts) {
|
||||
this.numContacts = dbContacts.values.length;
|
||||
const firstContact = dbContacts.values[0];
|
||||
const fullContact = databaseUtil.mapColumnsToValues(dbContacts.columns, [
|
||||
firstContact,
|
||||
]) as unknown as Contact;
|
||||
this.firstContactName = fullContact.name || "";
|
||||
|
||||
const contacts = await this.$getAllContacts();
|
||||
this.numContacts = contacts.length;
|
||||
if (contacts.length > 0) {
|
||||
this.firstContactName = contacts[0].name || "";
|
||||
}
|
||||
|
||||
this.visible = true;
|
||||
if (this.page === OnboardPage.Create) {
|
||||
// we'll assume that they've been through all the other pages
|
||||
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||
await this.$updateSettings({
|
||||
finishedOnboarding: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the onboarding dialog with optional completion actions
|
||||
*
|
||||
* @param done - Whether to mark onboarding as complete
|
||||
* @param goHome - Whether to navigate to home after closing
|
||||
*/
|
||||
async onClickClose(done?: boolean, goHome?: boolean) {
|
||||
this.visible = false;
|
||||
if (done) {
|
||||
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||
await this.$updateSettings({
|
||||
finishedOnboarding: true,
|
||||
});
|
||||
if (goHome) {
|
||||
|
||||
Reference in New Issue
Block a user