Live picks: 'Live stats · N orders' title, X icon in the phone popup
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
269fe03a80
commit
2665d3e6e0
2 files changed
+14
-14
No files matched your search
@@ -52,14 +52,14 @@ test("live picks: counts, podium stamp, expand/collapse, frozen after close", as
|
||||
await loginAs(page, first);
|
||||
await page.goto(`/order/${order.id}`);
|
||||
|
||||
const banner = page.getByRole("button", { name: /ordered/ });
|
||||
await expect(banner).toContainText("1 ordered · Veggie leads (1)");
|
||||
const banner = page.getByRole("button", { name: /stats/ });
|
||||
await expect(banner).toContainText("Live stats · 1 order");
|
||||
await expect(page.getByText("You were 1st to order!")).toBeVisible();
|
||||
await expect(page.getByText("1 person has ordered")).toBeHidden();
|
||||
|
||||
// polling picks up another participant without a reload
|
||||
await submit((await signIn()).userId, order.id, { burger: "Classic" });
|
||||
await expect(banner).toContainText("2 ordered", { timeout: 10_000 });
|
||||
await expect(banner).toContainText("Live stats · 2 orders", { timeout: 10_000 });
|
||||
|
||||
await banner.click();
|
||||
await expect(page.getByText("2 people have ordered")).toBeVisible();
|
||||
@@ -68,7 +68,7 @@ test("live picks: counts, podium stamp, expand/collapse, frozen after close", as
|
||||
|
||||
await api(`/api/orders/${order.id}/admin/status`, { userId: user.userId, method: "PUT", body: { closed: true } });
|
||||
await expect(page.getByText(/This order is closed/)).toBeVisible({ timeout: 10_000 });
|
||||
await expect(banner).toContainText("Final: 2 ordered");
|
||||
await expect(banner).toContainText("Final stats · 2 orders");
|
||||
});
|
||||
|
||||
test("live picks on phones: bolt button with count opens a popup and minimizes again", async ({ browser, user }) => {
|
||||
@@ -79,13 +79,13 @@ test("live picks on phones: bolt button with count opens a popup and minimizes a
|
||||
await loginAs(page, first);
|
||||
await page.goto(`/order/${order.id}`);
|
||||
|
||||
const fab = page.getByRole("button", { name: "Show live picks, 1 ordered" });
|
||||
const fab = page.getByRole("button", { name: "Show live stats, 1 order" });
|
||||
await expect(fab).toBeVisible();
|
||||
await fab.click();
|
||||
await expect(page.getByText("1 person has ordered")).toBeVisible();
|
||||
await page.reload();
|
||||
await expect(page.getByText("1 person has ordered")).toBeVisible(); // expanded state is remembered
|
||||
await page.getByRole("button", { name: /1 ordered/ }).click();
|
||||
await page.getByRole("button", { name: /stats · 1 order/ }).click();
|
||||
await expect(page.getByText("1 person has ordered")).toBeHidden();
|
||||
await expect(fab).toBeVisible();
|
||||
await page.close();
|
||||
@@ -99,7 +99,7 @@ test("live picks on phones: closed order gets the grey final button", async ({ b
|
||||
const page = await browser.newPage({ viewport: { width: 390, height: 800 } });
|
||||
await loginAs(page, first);
|
||||
await page.goto(`/order/${order.id}`);
|
||||
await expect(page.getByRole("button", { name: "Show live picks, 1 ordered" })).toHaveClass(/closed/);
|
||||
await expect(page.getByRole("button", { name: "Show live stats, 1 order" })).toHaveClass(/closed/);
|
||||
await page.close();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import { DownOutlined, LockOutlined, ThunderboltFilled } from "@ant-design/icons";
|
||||
import { CloseOutlined, DownOutlined, LockOutlined, ThunderboltFilled } from "@ant-design/icons";
|
||||
import { Card, Flex, Progress, Typography } from "antd";
|
||||
import type { OrderStats } from "../../lib/services/ordersService";
|
||||
import { getStoredValue, setStoredValue } from "../../lib/storage";
|
||||
@@ -49,20 +49,20 @@ function Bars({ stats }: { stats: OrderStats }) {
|
||||
}
|
||||
|
||||
function summary(stats: OrderStats, closed: boolean) {
|
||||
const top = stats.categories[0]?.items[0];
|
||||
return `${closed ? "Final: " : ""}${stats.participant_count} ordered${top ? ` · ${top.name} ${closed ? "led" : "leads"} (${top.count})` : ""}`;
|
||||
const n = stats.participant_count;
|
||||
return `${closed ? "Final" : "Live"} stats · ${n} ${n === 1 ? "order" : "orders"}`;
|
||||
}
|
||||
|
||||
const icon = (closed: boolean) => (closed ? <LockOutlined /> : <ThunderboltFilled />);
|
||||
|
||||
/** One card for both layouts: the animated banner is its header, the bars unfold below it. */
|
||||
function LivePicksCard({ stats, closed, open, onToggle }: { stats: OrderStats; closed: boolean; open: boolean; onToggle: () => void }) {
|
||||
function LivePicksCard({ stats, closed, open, onToggle, dismiss }: { stats: OrderStats; closed: boolean; open: boolean; onToggle: () => void; dismiss?: boolean }) {
|
||||
return (
|
||||
<div className={open ? "live-card open" : "live-card"}>
|
||||
<button className={closed ? "live-banner closed" : "live-banner"} aria-expanded={open} onClick={onToggle}>
|
||||
{icon(closed)}
|
||||
<span className="live-banner-text">{summary(stats, closed)}</span>
|
||||
<DownOutlined className={open ? "live-chevron open" : "live-chevron"} />
|
||||
{dismiss ? <CloseOutlined /> : <DownOutlined className={open ? "live-chevron open" : "live-chevron"} />}
|
||||
</button>
|
||||
{open && (
|
||||
<Card size="small" className="live-card-body" styles={{ body: { padding: "12px 16px" } }}>
|
||||
@@ -84,11 +84,11 @@ export function LivePicksFab({ stats, closed }: { stats: OrderStats; closed: boo
|
||||
const [open, setOpen] = useStoredFlag(EXPANDED_KEY);
|
||||
return (
|
||||
<div className="live-fab-wrap">
|
||||
{open && <LivePicksCard stats={stats} closed={closed} open onToggle={() => setOpen(false)} />}
|
||||
{open && <LivePicksCard stats={stats} closed={closed} open dismiss onToggle={() => setOpen(false)} />}
|
||||
{!open && (
|
||||
<button
|
||||
className={closed ? "live-fab closed" : "live-fab"}
|
||||
aria-label={`Show live picks, ${stats.participant_count} ordered`}
|
||||
aria-label={`Show live stats, ${stats.participant_count} ${stats.participant_count === 1 ? "order" : "orders"}`}
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<span className="live-fab-icon">{icon(closed)}</span>
|
||||
|
||||
Reference in new issue
Block a user