Add in-app quick start help

This commit is contained in:
Paul Huliganga 2026-04-22 09:27:52 -04:00
parent 7912eaf252
commit 0aba091d56
6 changed files with 311 additions and 0 deletions

View File

@ -269,11 +269,57 @@ tr:hover td { background: #FAFBFC; }
flex-shrink: 0;
}
/* ── Help / onboarding ── */
.help-layout { grid-template-columns: minmax(0, 1.3fr) minmax(280px, 0.7fr); }
.help-card { margin-bottom: 16px; }
.help-step-list,
.help-tip-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.help-step-item,
.help-tip-item,
.help-mini-card {
border: 1px solid var(--border);
background: #FAFBFC;
border-radius: var(--radius-sm);
padding: 12px 14px;
}
.help-step-item {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.help-step-title,
.help-mini-title {
font-size: var(--font-size-base);
font-weight: 700;
color: var(--text);
margin-bottom: 4px;
}
.help-step-desc,
.help-mini-text,
.help-tip-item {
font-size: var(--font-size-sm);
color: var(--text-muted);
line-height: 1.5;
}
.help-mini-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
/* ── Responsive ── */
@media (max-width: 900px) {
.stat-grid { grid-template-columns: repeat(3, 1fr); }
.two-col { grid-template-columns: 1fr; }
.help-layout { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
.stat-grid { grid-template-columns: repeat(2, 1fr); }
.help-mini-grid { grid-template-columns: 1fr; }
.help-step-item { flex-direction: column; align-items: flex-start; }
}

View File

@ -99,6 +99,12 @@
<span class="nav-label">Settings</span>
</a>
</li>
<li>
<a class="nav-item" data-route="#/help" href="#/help">
<span class="nav-icon"></span>
<span class="nav-label">Help</span>
</a>
</li>
</ul>
<!-- Bottom: customer context -->

View File

@ -41,6 +41,11 @@ router.register('#/settings', async () => {
renderSettings();
});
router.register('#/help', async () => {
const { renderHelp } = await import('./help.js');
renderHelp();
});
// ── Nav badge subscriptions ───────────────────────────────────────────────
subscribe('issueCount', count => {

211
web/static/js/help.js Normal file
View File

@ -0,0 +1,211 @@
import { state } from './state.js';
import { navigate } from './router.js';
const QUICK_START_KEY = 'migrator_quick_start_dismissed';
export function shouldShowQuickStart() {
try {
return localStorage.getItem(QUICK_START_KEY) !== '1';
} catch {
return true;
}
}
export function dismissQuickStart() {
try {
localStorage.setItem(QUICK_START_KEY, '1');
} catch {}
}
export function resetQuickStart() {
try {
localStorage.removeItem(QUICK_START_KEY);
} catch {}
}
function onboardingStatus() {
return {
adobeConnected: !!state.auth.adobe,
docusignConnected: !!state.auth.docusign,
docusignAccountChosen: !!state.auth.docusign && !state.auth.docusignAccountSelectionRequired,
templatesLoaded: (state.templates || []).length > 0,
};
}
function stepBadge(done, pendingLabel = 'Next') {
if (done) return '<span class="badge badge-green">Done</span>';
return `<span class="badge badge-amber">${pendingLabel}</span>`;
}
function quickStartStepsMarkup() {
const s = onboardingStatus();
return `
<div class="help-step-list">
<div class="help-step-item">
<div>
<div class="help-step-title">1. Connect Adobe Sign</div>
<div class="help-step-desc">Use the Adobe Sign chip in the top bar so the app can load your source templates.</div>
</div>
${stepBadge(s.adobeConnected)}
</div>
<div class="help-step-item">
<div>
<div class="help-step-title">2. Connect DocuSign</div>
<div class="help-step-desc">Use the Docusign chip to sign in and authorize the app for this browser session.</div>
</div>
${stepBadge(s.docusignConnected, s.adobeConnected ? 'Next' : 'After Adobe')}
</div>
<div class="help-step-item">
<div>
<div class="help-step-title">3. Choose the right DocuSign account</div>
<div class="help-step-desc">If your login has multiple accounts, select the exact target account before migrating anything.</div>
</div>
${stepBadge(s.docusignAccountChosen, s.docusignConnected ? 'Next' : 'After Sign-In')}
</div>
<div class="help-step-item">
<div>
<div class="help-step-title">4. Review templates and blockers</div>
<div class="help-step-desc">Start on Templates, scan the readiness badges, and use dry-run or single-template migration first.</div>
</div>
${stepBadge(s.templatesLoaded, s.docusignAccountChosen && s.adobeConnected ? 'Next' : 'Pending')}
</div>
<div class="help-step-item">
<div>
<div class="help-step-title">5. Verify after migration</div>
<div class="help-step-desc">Use Verification to send a test envelope and History to confirm what succeeded or failed.</div>
</div>
<span class="badge badge-blue">Recommended</span>
</div>
</div>
`;
}
export function quickStartCardMarkup() {
return `
<div class="card help-card" id="quick-start-card">
<div class="card-header">
<div>
<div class="card-title">Quick Start</div>
<div class="page-subtitle">New here? This is the shortest safe path through the tool.</div>
</div>
<div style="display:flex;gap:8px;flex-wrap:wrap">
<button class="btn btn-secondary btn-sm" id="btn-open-help-guide">Open Full Help</button>
<button class="btn btn-ghost btn-sm" id="btn-hide-quick-start">Hide</button>
</div>
</div>
<div class="card-body">
<div class="callout info" style="margin-bottom:16px">
<span class="callout-icon"></span>
This tool compares Adobe Sign templates with DocuSign templates, helps you migrate them, and gives you a place to verify the results afterward.
</div>
${quickStartStepsMarkup()}
</div>
</div>
`;
}
export function bindQuickStartCard(root = document) {
root.getElementById?.('btn-open-help-guide')?.addEventListener('click', () => navigate('#/help'));
root.getElementById?.('btn-hide-quick-start')?.addEventListener('click', () => {
dismissQuickStart();
root.getElementById('quick-start-card')?.remove();
});
}
export function renderHelp() {
const outlet = document.getElementById('router-outlet');
outlet.innerHTML = `
<div class="page-header">
<div>
<div class="page-title">Help & Quick Start</div>
<div class="page-subtitle">What this tool does, how to use it, and where to go next.</div>
</div>
<div class="page-actions">
<button class="btn btn-primary btn-sm" id="btn-help-go-templates">Go to Templates</button>
</div>
</div>
<div class="callout info">
<span class="callout-icon">🧭</span>
This app helps you migrate templates from Adobe Sign into DocuSign, review blockers and warnings, and send verification envelopes after migration.
</div>
<div class="two-col help-layout">
<div>
<div class="card help-card">
<div class="card-header">
<span class="card-title">Recommended First-Time Flow</span>
</div>
<div class="card-body">
${quickStartStepsMarkup()}
</div>
</div>
<div class="card help-card">
<div class="card-header">
<span class="card-title">What Each Screen Is For</span>
</div>
<div class="card-body">
<div class="help-mini-grid">
<div class="help-mini-card">
<div class="help-mini-title">Templates</div>
<div class="help-mini-text">Your main workspace. Review Adobe templates, readiness badges, blockers, and launch migrations.</div>
</div>
<div class="help-mini-card">
<div class="help-mini-title">Migration Results</div>
<div class="help-mini-text">See the most recent migration outcomes, including successes, partials, and failures.</div>
</div>
<div class="help-mini-card">
<div class="help-mini-title">Issues & Warnings</div>
<div class="help-mini-text">Focus on templates that need manual review before you migrate them confidently.</div>
</div>
<div class="help-mini-card">
<div class="help-mini-title">Verification</div>
<div class="help-mini-text">Send a test envelope after migration to validate the template works in DocuSign.</div>
</div>
<div class="help-mini-card">
<div class="help-mini-title">History & Audit</div>
<div class="help-mini-text">Review what was migrated, when it happened, and what account/session produced it.</div>
</div>
<div class="help-mini-card">
<div class="help-mini-title">Settings</div>
<div class="help-mini-text">Manage connections, default verification recipients, and reopen quick-start guidance.</div>
</div>
</div>
</div>
</div>
</div>
<div>
<div class="card help-card">
<div class="card-header">
<span class="card-title">Tips</span>
</div>
<div class="card-body">
<div class="help-tip-list">
<div class="help-tip-item"><strong>Pick the right DocuSign account.</strong> If you have many accounts, migrations go into the one you selected for this browser session.</div>
<div class="help-tip-item"><strong>Start with one template.</strong> Migrate a single clean template first before running a larger batch.</div>
<div class="help-tip-item"><strong>Use readiness badges.</strong> Blocked and Caveats are there to save you time before migration.</div>
<div class="help-tip-item"><strong>Verify afterward.</strong> A successful migration does not replace a real signing test.</div>
</div>
</div>
</div>
<div class="card help-card">
<div class="card-header">
<span class="card-title">If Something Looks Wrong</span>
</div>
<div class="card-body">
<div class="help-tip-list">
<div class="help-tip-item">If no templates appear, reconnect Adobe Sign and refresh the Templates page.</div>
<div class="help-tip-item">If DocuSign signs you into the wrong place, use <strong>Choose Account</strong> or <strong>Switch Account</strong>.</div>
<div class="help-tip-item">If the Templates page shows an error banner, fix that first before trying to migrate.</div>
</div>
</div>
</div>
</div>
</div>
`;
document.getElementById('btn-help-go-templates')?.addEventListener('click', () => navigate('#/templates'));
}

View File

@ -3,6 +3,8 @@
import { api } from './api.js';
import { escHtml } from './utils.js';
import { disconnectPlatform, showDocusignAccountPicker, switchAccount } from './auth.js';
import { navigate } from './router.js';
import { resetQuickStart } from './help.js';
const SETTINGS_KEY = 'migrator_settings';
@ -110,6 +112,33 @@ export function renderSettings() {
</div>
</div>
<div class="settings-section">
<div class="settings-section-header">
<div class="settings-section-title">Help & Onboarding</div>
<div class="settings-section-sub">Make it easy to get oriented again or share the app with a first-time tester</div>
</div>
<div class="settings-section-body">
<div class="setting-row">
<div class="setting-body">
<div class="setting-label">Open Full Help</div>
<div class="setting-desc">See the in-app guide with the recommended first-time flow and screen-by-screen overview.</div>
</div>
<div class="setting-control">
<button class="btn btn-secondary" id="btn-open-help">Open Help</button>
</div>
</div>
<div class="setting-row">
<div class="setting-body">
<div class="setting-label">Show Quick Start Again</div>
<div class="setting-desc">Re-enable the Templates quick-start card if you dismissed it earlier.</div>
</div>
<div class="setting-control">
<button class="btn btn-primary" id="btn-reset-quick-start">Show Quick Start</button>
</div>
</div>
</div>
</div>
<!-- Save -->
<div style="display:flex;gap:8px;align-items:center">
<button class="btn btn-primary" id="btn-save-settings">Save Settings</button>
@ -142,6 +171,15 @@ export function renderSettings() {
}
});
document.getElementById('btn-open-help')?.addEventListener('click', () => {
navigate('#/help');
});
document.getElementById('btn-reset-quick-start')?.addEventListener('click', () => {
resetQuickStart();
navigate('#/templates');
});
// Load connection info
_loadConnInfo();
}

View File

@ -4,6 +4,7 @@ import { api } from './api.js';
import { state, setState, updateDerivedState } from './state.js';
import { escHtml, formatDate, formatRelative, debounce, renderFieldIssues, bindFieldIssueToggles } from './utils.js';
import { navigate } from './router.js';
import { bindQuickStartCard, quickStartCardMarkup, shouldShowQuickStart } from './help.js';
// ── Readiness badge ────────────────────────────────────────────────────────
@ -96,6 +97,8 @@ function _render() {
</div>
` : ''}
${shouldShowQuickStart() ? quickStartCardMarkup() : ''}
<!-- Filter bar -->
<div class="filter-bar">
<input type="search" class="search-input" id="template-search"
@ -254,6 +257,8 @@ function _applyFilter(templates) {
// ── Event wiring ───────────────────────────────────────────────────────────
function _bindEvents() {
bindQuickStartCard(document);
// Search
const searchEl = document.getElementById('template-search');
if (searchEl) {