Skip to content
This repository has been archived by the owner on Dec 22, 2023. It is now read-only.

Commit

Permalink
Merge pull request #218 from mikenikles/improve-onboarding
Browse files Browse the repository at this point in the history
Improve onboarding
  • Loading branch information
Mike Nikles authored Oct 23, 2020
2 parents 7f0fbbf + 2cfece2 commit 519c65b
Show file tree
Hide file tree
Showing 9 changed files with 245 additions and 150 deletions.
7 changes: 4 additions & 3 deletions services/website/cypress/integration/onboarding.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ describe("/onboarding", () => {
});

it("should create a new website", () => {
cy.get('input[name="firstname"]').type("Tester");
cy.get('input[name="url"]').type("local-testing.com");
cy.get('input[id="firstName"]').type("Tester");
cy.get("button[type=button]").click();
cy.get('input[id="url"]').type("local-testing.com");
cy.get('select[name="timezone"]').select("America/Toronto");
cy.get("button[type=submit]").click();
cy.get("button[type=button]").click();
});
});
35 changes: 35 additions & 0 deletions services/website/src/components/onboarding/step-1.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script lang="ts">
import onboarding from "../../stores/onboarding";
import StepWrapper from "./step-wrapper.svelte";
let firstName = "";
const handleSubmit = () => {
$onboarding.user.firstName = firstName;
};
const handleKeyup = (event) => {
if (event.code === "Enter") {
handleSubmit();
}
};
</script>

<StepWrapper>
<div>
<label for="firstName" class="text-sm font-medium leading-5 text-gray-700">
What's your first name?
</label>
<div class="mt-1 rounded-md shadow-sm">
<input id="firstName" bind:value={firstName} on:keyup|preventDefault={handleKeyup} type="text" required class="appearance-none w-full px-3 py-2 border border-gray-300 rounded-md placeholder-gray-400 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 transition duration-150 ease-in-out sm:text-sm sm:leading-5">
</div>
</div>

<div class="mt-6">
<span class="w-full rounded-md shadow-sm">
<button type="button" on:click={handleSubmit} class="w-full flex justify-center mt-4 py-4 px-10 bg-blue-600 rounded-lg font-semibold text-white sm:mt-0">
Next: Configure your website
</button>
</span>
</div>
</StepWrapper>
98 changes: 98 additions & 0 deletions services/website/src/components/onboarding/step-2.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script lang="ts">
import { onDestroy } from "svelte";
import { addNewWebsite } from "../../api/onboarding";
import { fetchUniqueVisitorsOnOnboardingPage } from "../../api/stats";
import dateRange from "../../stores/date-range";
import onboarding from "../../stores/onboarding";
import { session } from "../../stores/session";
import StepWrapper from "./step-wrapper.svelte";
import TimezoneSelect from "../timezone-select.svelte";
export let hasUserAlreadyConfiguredSite: boolean;
export let isUrlInvalid: boolean;
let fetchUniqueVisitorsInterval: number;
$: existingUserSites = Object.keys($onboarding.user.sites || {}) || [];
$: hasUserAlreadyConfiguredSite = existingUserSites.includes($onboarding.url);
$: isUrlInvalid = hasUserAlreadyConfiguredSite || $onboarding.isSiteAlreadyConfiguredGlobally;
const handleSubmit = async () => {
const firstName = $onboarding.user.firstName;
const url = $onboarding.url;
const timezone = $onboarding.timezone;
const responseCode = await addNewWebsite({firstName, url, timezone});
switch (responseCode) {
case 201:
$onboarding.isSiteAdded = true;
$session.user.sites[url] = {};
dateRange.setPreset("today");
fetchUniqueVisitorsInterval = setInterval(() => {
fetchUniqueVisitorsOnOnboardingPage(window.fetch, window.location.hostname, url);
}, 10000);
break;
case 400:
$onboarding.isSiteAlreadyConfiguredGlobally = true;
break;
}
};
onDestroy(() => {
if (fetchUniqueVisitorsInterval) {
window.clearInterval(fetchUniqueVisitorsInterval);
}
});
</script>

<style>
button:disabled {
@apply bg-indigo-500;
@apply cursor-not-allowed;
}
</style>

<StepWrapper>
<div>
<label for="url" class="text-sm font-medium leading-5 text-gray-700">
What's your website URL?
</label>
<div class="mt-1 relative flex rounded-md shadow-sm">
<span class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 sm:text-sm">
http(s)://www.
</span>
<input id="url" bind:value={$onboarding.url} on:focus={() => $onboarding.isSiteAlreadyConfiguredGlobally = false} type="text" name="url" required class="px-3 py-2 w-full border border-gray-300 rounded-none rounded-r-md focus:outline-none focus:shadow-outline-blue focus:border-blue-300 sm:text-sm sm:leading-5">
{#if isUrlInvalid && !$onboarding.isSiteAdded}
<div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-red-500" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
{/if}
</div>
<p class="mt-2 text-sm text-red-600">
{#if !$onboarding.isSiteAdded && hasUserAlreadyConfiguredSite}
You've already configured this website.
{:else if !$onboarding.isSiteAdded && $onboarding.isSiteAlreadyConfiguredGlobally}
This site has already been configured. If it belongs to you, please contact us.
{/if}
</p>
</div>

<div class="mt-6">
<label for="url" class="text-sm font-medium leading-5 text-gray-700">
What's your preferred reporting timezone
</label>
<div class="mt-1 rounded-md shadow-sm">
<TimezoneSelect name="timezone" />
</div>
</div>

<div class="mt-6">
<span class="w-full rounded-md shadow-sm">
<button type="button" on:click={handleSubmit} disabled={isUrlInvalid} class="w-full flex justify-center mt-4 py-4 px-10 bg-blue-600 rounded-lg font-semibold text-white sm:mt-0">
Let's go
</button>
</span>
</div>
</StepWrapper>
29 changes: 29 additions & 0 deletions services/website/src/components/onboarding/step-3.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script lang="ts">
import onboarding from "../../stores/onboarding";
import StepWrapper from "./step-wrapper.svelte";
import UniqueVisitors from "../stats/unique-visitors.svelte";
$: script = `<script async defer src="https://your-analytics.org/ya.js" data-domain="${$onboarding.url}"><\/script>`;
const copyScriptToClipboard = () => {
const textarea = document.getElementById('script') as HTMLTextAreaElement;
textarea.focus();
textarea.select();
document.execCommand('copy');
};
</script>

<StepWrapper>
<p>Add the following script to all pages you want to track on your website.</p>
<div class="relative mt-6">
<textarea id="script" value={script} rows="3" readonly class="w-full p-2 bg-gray-100 resize-none"></textarea>
<button on:click={copyScriptToClipboard}>
<svg class="absolute" style="top: 24px; right: 12px;" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
</button>
</div>
<p class="mt-6">Once added, please visit <a href="https://{$onboarding.url}" target="_blank" rel="noopener" class="text-pink-600 hover:underline">{$onboarding.url}</a> to see the first few visits logged below.</p>
<div class="relative mt-6 pb-6 flex justify-center">
<UniqueVisitors />
</div>
<p class="mt-6">Don't want to wait? <a href="/{$onboarding.url}" class="text-pink-600 hover:underline">Go to your dashboard.</a></p>
</StepWrapper>
22 changes: 22 additions & 0 deletions services/website/src/components/onboarding/step-header.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script lang="ts">
export let label: string;
export let stepNumber: number;
export let isUpcoming: boolean = false;
</script>

<style>
.isUpcoming div {
@apply border-gray-200;
}
.isUpcoming h3 {
@apply text-gray-500;
}
</style>

<li class:isUpcoming class="md:flex-1">
<div class="pl-4 py-2 block border-l-4 border-indigo-600 md:pl-0 md:pt-4 md:pb-0 md:border-l-0 md:border-t-4">
<h3 class="text-xs leading-4 text-indigo-600 font-semibold uppercase">Step {stepNumber}</h3>
<p class="text-sm leading-5 font-medium">{label}</p>
</div>
</li>
10 changes: 10 additions & 0 deletions services/website/src/components/onboarding/step-wrapper.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script lang="ts">
import { fly } from 'svelte/transition';
import Card from "../card.svelte";
</script>

<div in:fly={{x:1000, delay:500, duration:500}} out:fly={{x:-500, duration:500}}>
<Card clazz="p-4">
<slot />
</Card>
</div>
6 changes: 3 additions & 3 deletions services/website/src/components/timezone-select.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script lang="ts">
import onboarding from "../stores/onboarding";
export let name: string;
/**
Expand Down Expand Up @@ -607,11 +609,9 @@
"US/Samoa": "−11:00",
"Etc/GMT+12": "−12:00"
};
let userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
</script>

<select required {name} bind:value={userTimezone} class="form-select w-full sm:text-sm sm:leading-5">
<select required {name} bind:value={$onboarding.timezone} class="form-select w-full sm:text-sm sm:leading-5">
{#each Object.entries(timezones) as [tzName, tzOffset]}
<option
value={tzName}>
Expand Down
Loading

1 comment on commit 519c65b

@vercel
Copy link

@vercel vercel bot commented on 519c65b Oct 23, 2020

Choose a reason for hiding this comment

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

Please sign in to comment.