Skip to content
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
6 changes: 3 additions & 3 deletions apps/web/src/components/ReportToast.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('ReportToast', () => {

it('offers a connection-problem report after the chooser is dismissed, until dismissed', () => {
const { container } = render(<ReportToast meters={meters([channel({ cancelled: true })])} />);
const link = screen.getByRole('link', { name: /tell us which one/i });
const link = screen.getByRole('link', { name: /let us know/i });
expect(link.getAttribute('href')).toContain('template=connection-problem.yml');
fireEvent.click(screen.getByRole('button', { name: /dismiss/i }));
expect(container.firstChild).toBeNull();
Expand All @@ -59,8 +59,8 @@ describe('ReportToast', () => {
});
const live = [channel({ state: 'live', driverId: 'ut181a', deviceName: 'UT181A' })];
const { container, unmount } = render(<ReportToast meters={meters(live, { describe })} />);
expect(screen.getByText(/not yet confirmed on real hardware/i)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: /report it/i }));
expect(screen.getByText(/how is your meter working for you/i)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: /let us know/i }));
await waitFor(() => expect(open).toHaveBeenCalled());
expect(open.mock.calls[0]![0]).toContain('template=device-report.yml');
await waitFor(() => expect(container.firstChild).toBeNull());
Expand Down
21 changes: 8 additions & 13 deletions apps/web/src/components/ReportToast.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// A dismissible, non-blocking toast inviting a device report (see lib/report.ts). Two cases:
// * a real meter is live on a driver not yet confirmed on hardware → "does it work?". Dismissing
// * a real meter is live on a driver not yet confirmed on hardware → "how is it working?". Dismissing
// or reporting is remembered per driver, so it asks once.
// * the chooser was dismissed or connecting failed → "not in the list, or won't connect?".
// * the chooser was dismissed or connecting failed → "trouble finding or connecting?".
// Dismissing hides it until the next cancel/failure.
// Both open a pre-filled GitHub issue form in a new tab; the user reviews and submits it there.

import { useEffect, useState } from 'react';
import type { MeterChannel, Meters } from '@libreble/multimeter-react';
import type { Meters } from '@libreble/multimeter-react';
import { connectionProblemUrl, deviceReportUrl, verification } from '../lib/report';

const DONE_KEY = (driverId: string) => `multimeter.reportDone.${driverId}`;
Expand Down Expand Up @@ -36,7 +36,7 @@ export function ReportToast({ meters }: { meters: Meters }) {
c =>
c.state === 'live' &&
c.driverId !== null &&
verification(c.driverId)?.tier !== 'live-tested' &&
verification(c.driverId) !== 'live-tested' &&
!done.has(c.driverId) &&
!isDone(c.driverId),
);
Expand All @@ -63,12 +63,9 @@ export function ReportToast({ meters }: { meters: Meters }) {
};
return (
<Toast onDismiss={finish}>
<p>
<strong className="font-semibold text-zinc-100">{name(unconfirmed)}</strong> is{' '}
{verification(driverId)?.text}. Does it read right?
</p>
<p>How is your meter working for you?</p>
<button type="button" onClick={() => void report()} className={ACTION}>
Report it
Let us know
</button>
</Toast>
);
Expand All @@ -77,15 +74,15 @@ export function ReportToast({ meters }: { meters: Meters }) {
if (problem && !problemDismissed) {
return (
<Toast onDismiss={() => setProblemDismissed(true)}>
<p>Meter not in the list, or won't connect?</p>
<p>Trouble finding or connecting your meter?</p>
<a
href={connectionProblemUrl(problem.error)}
target="_blank"
rel="noopener noreferrer"
onClick={() => setProblemDismissed(true)}
className={ACTION}
>
Tell us which one
Let us know
</a>
</Toast>
);
Expand All @@ -94,8 +91,6 @@ export function ReportToast({ meters }: { meters: Meters }) {
return null;
}

const name = (c: MeterChannel) => c.deviceName ?? 'This meter';

const ACTION =
'mt-2 inline-block rounded-md bg-emerald-500 px-3 py-1 text-sm font-semibold text-emerald-950 hover:bg-emerald-400';

Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/lib/report.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ describe('device report URLs', () => {
});

it('maps drivers to their verification tier', () => {
expect(verification('uni-t')?.tier).toBe('live-tested');
expect(verification('ut181a')?.text).toBe('not yet confirmed on real hardware');
expect(verification('uni-t')).toBe('live-tested');
expect(verification('ut181a')).toBe('ported-unverified');
expect(verification(null)).toBeNull();
});
});
11 changes: 2 additions & 9 deletions apps/web/src/lib/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@ import type { GattDescription } from '@libreble/multimeter-react';

const ISSUES = 'https://github.com/libreble/multimeter/issues/new';

const VERIFICATION_TEXT = {
'live-tested': 'confirmed on real hardware',
'app-verified': 'checked against the vendor app, not yet on a real meter',
'ported-unverified': 'not yet confirmed on real hardware',
} as const;

function browser(): string {
return typeof navigator === 'undefined' ? 'unknown' : navigator.userAgent;
}
Expand All @@ -23,10 +17,9 @@ function issueUrl(template: string, title: string, fields: Record<string, string
return `${ISSUES}?${q}`;
}

/** A driver's verification tier plus a plain-language phrase for the report prompt. */
/** A driver's verification tier, or null for no/unknown driver. */
export function verification(driverId: string | null) {
const d = driverId ? driverById(driverId) : undefined;
return d ? { tier: d.verification, text: VERIFICATION_TEXT[d.verification] } : null;
return (driverId && driverById(driverId)?.verification) || null;
}

export function connectedSummary(driverId: string | null, g: GattDescription | null): string {
Expand Down
Loading