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

Playground Layout: Put visitor ID in Identification column #148

Merged
merged 20 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion e2e/playground.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ test.beforeEach(async ({ page }) => {
test.describe('Playground page', () => {
test('Page renders basic skeleton elements', async ({ page }) => {
await page.getByText('Fingerprint Pro Playground', { exact: true }).waitFor();
await page.getByText('Welcome, this is your visitor ID').waitFor();
await page.getByText('Your Visitor ID is').waitFor();
await page.getByTestId(TEST_ID.refreshButton).first().waitFor();

await page.getByText('Identification', { exact: true }).waitFor();
Expand Down
223 changes: 124 additions & 99 deletions src/app/playground/Playground.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { FunctionComponent } from 'react';
import { FunctionComponent, useEffect, ReactNode } from 'react';
import { CollapsibleJsonViewer } from '../../client/components/common/CodeSnippet/CodeSnippet';
import dynamic from 'next/dynamic';
import SignalTable, { TableCellData } from './components/SignalTable';
Expand Down Expand Up @@ -32,6 +32,7 @@ import {
} from '../../client/components/common/Collapsible/Collapsible';
import { ChevronSvg } from '../../client/img/chevronSvg';
import { pluralize } from '../../shared/utils';
import { motion } from 'framer-motion';

const PLAYGROUND_COPY = {
androidOnly: 'Applicable only to Android devices',
Expand Down Expand Up @@ -63,6 +64,17 @@ const DocsLink: FunctionComponent<{ children: string; href: string; style?: Reac
// Map cannot be server-side rendered
const Map = dynamic(() => import('./components/Map'), { ssr: false });

const TableTitle = ({ children }: { children: ReactNode }) => (
<motion.h3
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.3 }}
className={styles.tableTitle}
>
{children}
</motion.h3>
);

function Playground() {
const {
agentResponse,
Expand All @@ -75,6 +87,13 @@ function Playground() {
serverError,
} = usePlaygroundSignals();

/**
* Prevent restoring scroll position on page refresh since there is nothing to scroll to while the data is being loaded
*/
useEffect(() => {
window.history.scrollRestoration = 'manual';
}, []);

if (agentError) {
return <Alert severity={'error'}>JavaScript Agent Error: {agentError.message}.</Alert>;
}
Expand Down Expand Up @@ -147,14 +166,14 @@ function Playground() {
content: (
<>
{latitude && longitude && (
<div>
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.25 }}>
<Map
key={[latitude, longitude].toString()}
position={[latitude, longitude]}
zoom={zoom}
height='95px'
/>
</div>
</motion.div>
)}
</>
),
Expand Down Expand Up @@ -448,120 +467,126 @@ function Playground() {
</h1>
<p>Analyze your browser with Fingerprint Pro and see all the available signals.</p>
</Container>
{agentResponse && (
<Container size='large'>
<div className={styles.visitorIdBox}>
<p>Welcome, this is your visitor ID</p>
<h2 className={styles.visitorId}>{agentResponse?.visitorId}</h2>
</div>
</Container>
)}
{!cachedEvent ? (
<Container size='large'>
<div className={styles.runningIntelligence}>
<Spinner size={64} />
<Container size='large'>
<div className={styles.runningIntelligence}>
{!cachedEvent ? (
<h2>
Running Device Intelligence<span className={styles.blink}>_</span>
</h2>
</div>
</Container>
) : (
<>
<Container size='large'>
) : (
<RefreshButton
loading={isLoadingAgentResponse || isLoadingServerResponse}
getAgentData={getAgentData}
className={styles.reloadButton}
/>

<div className={styles.tablesContainer}>
)}
</div>
</Container>
<>
<Container size='large'>
<div className={styles.tablesContainer}>
{agentResponse ? (
<MyCollapsible defaultOpen>
<h3 className={styles.tableTitle}>
<TableTitle>
Identification{' '}
<MyCollapsibleTrigger>
<ChevronSvg />
</MyCollapsibleTrigger>
</h3>
</TableTitle>
<MyCollapsibleContent>
<SignalTable data={identificationSignals} />
</MyCollapsibleContent>
</MyCollapsible>
<div className={styles.visitorIdBox}>
<p>Your Visitor ID is </p>
<h2 className={styles.visitorId}>{agentResponse?.visitorId}</h2>
</div>

<MyCollapsible defaultOpen>
<h3 className={styles.tableTitle}>
Smart signals{' '}
<MyCollapsibleTrigger>
<ChevronSvg />
</MyCollapsibleTrigger>
</h3>
<MyCollapsibleContent>
<SignalTable data={smartSignals} />
</MyCollapsibleContent>
</MyCollapsible>
<MyCollapsible defaultOpen>
<h3 className={styles.tableTitle}>
Mobile Smart signals{' '}
<MyCollapsibleTrigger>
<ChevronSvg />
</MyCollapsibleTrigger>
</h3>
<MyCollapsibleContent>
<SignalTable data={mobileSmartSignals} />
<SignalTable data={identificationSignals} />
</MyCollapsibleContent>
</MyCollapsible>
</div>
</Container>

<Container size='large' className={styles.isSection}>
<h2 className={styles.sectionTitle}>How to use this demo</h2>
<HowToUseThisPlayground />
</Container>
<Container size='large' className={classnames(styles.isSection, styles.jsonSection)}>
<div className={styles.jsonContainer}>
<div>
<h4 className={styles.jsonTitle}>
JavaScript Agent Response {isLoadingAgentResponse && <Spinner size={16} />}
</h4>
<CollapsibleJsonViewer
dataTestId={TEST_IDS.playground.agentResponseJSON}
json={displayedAgentResponse ?? {}}
/>
</div>
<div>
<h4 className={styles.jsonTitle}>
Server API Response {isLoadingServerResponse && <Spinner size={16} />}
</h4>
<CollapsibleJsonViewer
dataTestId={TEST_IDS.playground.serverResponseJSON}
json={usedIdentificationEvent ?? {}}
/>
) : (
// Spacer element to push footer down when no data is ready
<div style={{ height: '800px' }} />
)}
{cachedEvent ? (
<>
<MyCollapsible defaultOpen>
<TableTitle>
Smart signals{' '}
<MyCollapsibleTrigger>
<ChevronSvg />
</MyCollapsibleTrigger>
</TableTitle>
<MyCollapsibleContent>
<SignalTable data={smartSignals} />
</MyCollapsibleContent>
</MyCollapsible>
<MyCollapsible defaultOpen>
<TableTitle>
Mobile Smart signals{' '}
<MyCollapsibleTrigger>
<ChevronSvg />
</MyCollapsibleTrigger>
</TableTitle>
<MyCollapsibleContent>
<SignalTable data={mobileSmartSignals} />
</MyCollapsibleContent>
</MyCollapsible>
</>
) : null}
</div>
</Container>
{cachedEvent ? (
<>
<Container size='large' className={styles.isSection}>
<h2 className={styles.sectionTitle}>How to use this demo</h2>
<HowToUseThisPlayground />
</Container>
<Container size='large' className={classnames(styles.isSection, styles.jsonSection)}>
<div className={styles.jsonContainer}>
<div>
<h4 className={styles.jsonTitle}>
JavaScript Agent Response {isLoadingAgentResponse && <Spinner size={16} />}
</h4>
<CollapsibleJsonViewer
dataTestId={TEST_IDS.playground.agentResponseJSON}
json={displayedAgentResponse ?? {}}
/>
</div>
<div>
<h4 className={styles.jsonTitle}>
Server API Response {isLoadingServerResponse && <Spinner size={16} />}
</h4>
<CollapsibleJsonViewer
dataTestId={TEST_IDS.playground.serverResponseJSON}
json={usedIdentificationEvent ?? {}}
/>
</div>
</div>
</div>
</Container>
<Container size='large' className={styles.learnMoreSection}>
<h2 className={styles.sectionTitle}>Learn more</h2>
</Container>
<ResourceLinks
resources={[
{
title: 'Quick Start Guide',
url: 'https://dev.fingerprint.com/docs/quick-start-guide',
type: 'Article',
},
{
title: 'What is Fingerprint',
url: 'https://dev.fingerprint.com/docs/what-is-fingerprint',
type: 'Article',
},
{
title: 'Intro to Device Intelligence Webinar',
url: 'https://www.youtube.com/watch?v=YTRmWUeQWyY',
type: 'Webinar',
},
]}
/>
</>
)}
</Container>
<Container size='large' className={styles.learnMoreSection}>
<h2 className={styles.sectionTitle}>Learn more</h2>
</Container>
<ResourceLinks
resources={[
{
title: 'Quick Start Guide',
url: 'https://dev.fingerprint.com/docs/quick-start-guide',
type: 'Article',
},
{
title: 'What is Fingerprint',
url: 'https://dev.fingerprint.com/docs/what-is-fingerprint',
type: 'Article',
},
{
title: 'Intro to Device Intelligence Webinar',
url: 'https://www.youtube.com/watch?v=YTRmWUeQWyY',
type: 'Webinar',
},
]}
/>
</>
) : null}
</>
</>
);
}
Expand Down
8 changes: 2 additions & 6 deletions src/app/playground/components/RefreshButton.module.scss
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
.refreshButton.refreshButton {
display: flex;
padding: rem(12px) rem(24px);
padding: 16px;
font-weight: 500;
font-size: 16px;
font-weight: 500;
font-weight: 400;
line-height: 150%; /* 24px */
white-space: unset;

@include media('<=phoneLandscape') {
font-size: 14px;
}

img {
transition: scale 0.2s ease;
margin-left: rem(4px);
Expand Down
12 changes: 9 additions & 3 deletions src/app/playground/components/SignalTable.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ReactNode, FunctionComponent } from 'react';
import styles from './SignalTable.module.scss';
import { motion } from 'framer-motion';

export type TableCellData = {
content: ReactNode | ReactNode[];
Expand All @@ -10,14 +11,19 @@ const SignalTable: FunctionComponent<{ data: TableCellData[][] }> = ({ data }) =
return (
<table className={styles.signalTable}>
<tbody>
{data.map((row, i) => (
<tr key={i}>
{data.map((row, rowIndex) => (
<motion.tr
key={rowIndex}
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25, delay: rowIndex * 0.1 }}
>
{row.map((cell, j) => (
<td key={j} className={cell.className}>
{cell.content}
</td>
))}
</tr>
</motion.tr>
))}
</tbody>
</table>
Expand Down
Loading
Loading