Skip to content

Commit

Permalink
Expand bottle panel to include overview
Browse files Browse the repository at this point in the history
  • Loading branch information
dcramer committed Dec 20, 2023
1 parent 5d3af4a commit 859b7c1
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 161 deletions.
41 changes: 41 additions & 0 deletions apps/web/app/components/bottleHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { Bottle } from "@peated/server/types";
import BottleIcon from "@peated/web/components/assets/Bottle";
import { Link } from "@remix-run/react";
import { formatCategoryName } from "../lib/strings";
import BottleMetadata from "./bottleMetadata";
import PageHeader from "./pageHeader";

export default function BottleHeader({ bottle }: { bottle: Bottle }) {
return (
<PageHeader
icon={BottleIcon}
title={bottle.fullName}
titleExtra={
<BottleMetadata
data={bottle}
className="w-full truncate text-center text-slate-500 lg:text-left"
/>
}
metadata={
(bottle.category || bottle.statedAge) && (
<div className="flex w-full min-w-[150px] flex-col items-center justify-center gap-x-1 text-slate-500 lg:w-auto lg:items-end">
<div>
{bottle.category && (
<Link
to={`/bottles?category=${encodeURIComponent(
bottle.category,
)}`}
>
{formatCategoryName(bottle.category)}
</Link>
)}
</div>
<div>
{bottle.statedAge ? `Aged ${bottle.statedAge} years` : null}
</div>
</div>
)
}
/>
);
}
68 changes: 68 additions & 0 deletions apps/web/app/components/bottleOverview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { Bottle } from "@peated/server/types";
import RobotImage from "@peated/web/assets/robot.png";
import { Fragment } from "react";
import BottleTagDistribution from "./bottleTagDistribution.client";
import { ClientOnly } from "./clientOnly";
import Markdown from "./markdown";
import QueryBoundary from "./queryBoundary";

export default function BottleOverview({ bottle }: { bottle: Bottle }) {
return (
<>
<div className="my-6 px-3 md:px-0">
<ClientOnly
fallback={
<div
className="animate-pulse bg-slate-800"
style={{ height: 200 }}
/>
}
>
{() => (
<QueryBoundary
fallback={
<div
className="animate-pulse bg-slate-800"
style={{ height: 200 }}
/>
}
loading={<Fragment />}
>
<BottleTagDistribution bottleId={bottle.id} />
</QueryBoundary>
)}
</ClientOnly>
</div>

{(bottle.description || bottle.tastingNotes) && (
<div className="my-6 px-3 md:px-0">
{bottle.description && (
<div className="flex space-x-4">
<div className="prose prose-invert -mt-5 max-w-none flex-auto">
<Markdown content={bottle.description} />
</div>
<img src={RobotImage} className="hidden h-40 w-40 sm:block" />
</div>
)}
{bottle.tastingNotes && (
<>
<h3 className="text-highlight text-lg font-bold">
Tasting Notes
</h3>
<div className="prose prose-invert max-w-none flex-auto">
<dl>
<dt>Nose</dt>
<dd>{bottle.tastingNotes.nose}</dd>
<dt>Palate</dt>
<dd>{bottle.tastingNotes.palate}</dd>
<dt>Finish</dt>
<dd>{bottle.tastingNotes.finish}</dd>
</dl>
</div>
</>
)}
</div>
)}
</>
);
}
50 changes: 14 additions & 36 deletions apps/web/app/components/bottlePanel.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { type Bottle } from "@peated/server/types";
import BottleIcon from "@peated/web/components/assets/Bottle";
import { Link } from "@remix-run/react";
import { type ComponentPropsWithoutRef } from "react";
import useAuth from "../hooks/useAuth";
import { formatCategoryName } from "../lib/strings";
import BottleMetadata from "./bottleMetadata";
import BottlePriceHistory from "./bottlePriceHistory";
import { trpc } from "../lib/trpc";
import BottleHeader from "./bottleHeader";
import BottleOverview from "./bottleOverview";
import BottlePriceHistory from "./bottlePriceHistory.client";
import Button from "./button";
import { ClientOnly } from "./clientOnly";
import CollectionAction from "./collectionAction";
import PageHeader from "./pageHeader";
import LoadingIndicator from "./loadingIndicator";
import QueryBoundary from "./queryBoundary";
import ShareButton from "./shareButton";
import SidePanel, { SidePanelHeader } from "./sidePanel";
Expand All @@ -25,6 +24,8 @@ export default function BottlePanel({
} & Omit<ComponentPropsWithoutRef<typeof SidePanel>, "children">) {
const { user } = useAuth();

const { data, isLoading } = trpc.bottleById.useQuery(bottle.id);

const stats = [
{
name: "Avg Rating",
Expand All @@ -39,36 +40,7 @@ export default function BottlePanel({
return (
<SidePanel {...props}>
<SidePanelHeader>
<PageHeader
icon={BottleIcon}
title={bottle.fullName}
titleExtra={
<BottleMetadata
data={bottle}
className="w-full truncate text-center text-slate-500 lg:text-left"
/>
}
metadata={
(bottle.category || bottle.statedAge) && (
<div className="flex w-full min-w-[150px] flex-col items-center justify-center gap-x-1 text-slate-500 lg:w-auto lg:items-end">
<div>
{bottle.category && (
<Link
to={`/bottles?category=${encodeURIComponent(
bottle.category,
)}`}
>
{formatCategoryName(bottle.category)}
</Link>
)}
</div>
<div>
{bottle.statedAge ? `Aged ${bottle.statedAge} years` : null}
</div>
</div>
)
}
/>
<BottleHeader bottle={bottle} />
</SidePanelHeader>

<div className="my-8 flex justify-center gap-4 lg:justify-start">
Expand Down Expand Up @@ -109,6 +81,12 @@ export default function BottlePanel({
</div>
</div>
</div>

{isLoading ? (
<LoadingIndicator />
) : data ? (
<BottleOverview bottle={data} />
) : null}
</SidePanel>
);
}
30 changes: 30 additions & 0 deletions apps/web/app/components/bottleTagDistribution.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { trpc } from "../lib/trpc";
import { DistributionChart } from "./distributionChart";

export default function BottleTagDistribution({
bottleId,
}: {
bottleId: number;
}) {
const { data } = trpc.bottleTagList.useQuery({
bottle: bottleId,
});

if (!data) return null;

const { results, totalCount } = data;

if (!results.length) return null;

return (
<DistributionChart
items={results.map((t) => ({
name: t.tag,
count: t.count,
tag: t.tag,
}))}
totalCount={totalCount}
to={(item) => `/bottles?tag=${encodeURIComponent(item.name)}`}
/>
);
}
92 changes: 2 additions & 90 deletions apps/web/app/routes/bottles.$bottleId._index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import { makeTRPCClient } from "@peated/server/lib/trpc";
import type { Bottle } from "@peated/server/types";
import RobotImage from "@peated/web/assets/robot.png";
import { ClientOnly } from "@peated/web/components/clientOnly";
import { DistributionChart } from "@peated/web/components/distributionChart";
import Markdown from "@peated/web/components/markdown";
import QueryBoundary from "@peated/web/components/queryBoundary";
import config from "@peated/web/config";
import { trpc } from "@peated/web/lib/trpc";
import { useOutletContext } from "@remix-run/react";
import { captureException } from "@sentry/remix";
import { Fragment } from "react";
import { type SitemapFunction } from "remix-sitemap";
import BottleOverview from "../components/bottleOverview";

export const sitemap: SitemapFunction = async ({
config: sitemapConfig,
Expand All @@ -37,89 +31,7 @@ export const sitemap: SitemapFunction = async ({
return output;
};

const BottleTagDistribution = ({ bottleId }: { bottleId: number }) => {
const { data } = trpc.bottleTagList.useQuery({
bottle: bottleId,
});

if (!data) return null;

const { results, totalCount } = data;

if (!results.length) return null;

return (
<DistributionChart
items={results.map((t) => ({
name: t.tag,
count: t.count,
tag: t.tag,
}))}
totalCount={totalCount}
to={(item) => `/bottles?tag=${encodeURIComponent(item.name)}`}
/>
);
};

export default function BottleDetails() {
const { bottle } = useOutletContext<{ bottle: Bottle }>();

return (
<>
<div className="my-6 px-3 md:px-0">
<ClientOnly
fallback={
<div
className="animate-pulse bg-slate-800"
style={{ height: 200 }}
/>
}
>
{() => (
<QueryBoundary
fallback={
<div
className="animate-pulse bg-slate-800"
style={{ height: 200 }}
/>
}
loading={<Fragment />}
>
<BottleTagDistribution bottleId={bottle.id} />
</QueryBoundary>
)}
</ClientOnly>
</div>

{(bottle.description || bottle.tastingNotes) && (
<div className="my-6 px-3 md:px-0">
{bottle.description && (
<div className="flex space-x-4">
<div className="prose prose-invert -mt-5 max-w-none flex-auto">
<Markdown content={bottle.description} />
</div>
<img src={RobotImage} className="hidden h-40 w-40 sm:block" />
</div>
)}
{bottle.tastingNotes && (
<>
<h3 className="text-highlight text-lg font-bold">
Tasting Notes
</h3>
<div className="prose prose-invert max-w-none flex-auto">
<dl>
<dt>Nose</dt>
<dd>{bottle.tastingNotes.nose}</dd>
<dt>Palate</dt>
<dd>{bottle.tastingNotes.palate}</dd>
<dt>Finish</dt>
<dd>{bottle.tastingNotes.finish}</dd>
</dl>
</div>
</>
)}
</div>
)}
</>
);
return <BottleOverview bottle={bottle} />;
}
38 changes: 3 additions & 35 deletions apps/web/app/routes/bottles.$bottleId.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Menu } from "@headlessui/react";
import { EllipsisVerticalIcon } from "@heroicons/react/20/solid";
import BottleIcon from "@peated/web/components/assets/Bottle";
import BottleMetadata from "@peated/web/components/bottleMetadata";
import Button from "@peated/web/components/button";
import { ClientOnly } from "@peated/web/components/clientOnly";
import ConfirmationButton from "@peated/web/components/confirmationButton";
Expand All @@ -18,11 +16,10 @@ import { type MetaFunction } from "@remix-run/node";
import { Link, Outlet, useLoaderData, useNavigate } from "@remix-run/react";
import { json } from "@remix-run/server-runtime";
import invariant from "tiny-invariant";
import BottlePriceHistory from "../components/bottlePriceHistory";
import BottleHeader from "../components/bottleHeader";
import BottlePriceHistory from "../components/bottlePriceHistory.client";
import CollectionAction from "../components/collectionAction";
import PageHeader from "../components/pageHeader";
import { makeIsomorphicLoader } from "../lib/isomorphicLoader";
import { formatCategoryName } from "../lib/strings";

export const { loader, clientLoader } = makeIsomorphicLoader(
async ({ params, context: { trpc } }) => {
Expand Down Expand Up @@ -92,36 +89,7 @@ export default function BottleDetails() {
return (
<Layout>
<div className="w-full p-3 lg:py-0">
<PageHeader
icon={BottleIcon}
title={bottle.fullName}
titleExtra={
<BottleMetadata
data={bottle}
className="w-full truncate text-center text-slate-500 lg:text-left"
/>
}
metadata={
(bottle.category || bottle.statedAge) && (
<div className="flex w-full min-w-[150px] flex-col items-center justify-center gap-x-1 text-slate-500 lg:w-auto lg:items-end">
<div>
{bottle.category && (
<Link
to={`/bottles?category=${encodeURIComponent(
bottle.category,
)}`}
>
{formatCategoryName(bottle.category)}
</Link>
)}
</div>
<div>
{bottle.statedAge ? `Aged ${bottle.statedAge} years` : null}
</div>
</div>
)
}
/>
<BottleHeader bottle={bottle} />

<div className="my-8 flex justify-center gap-4 lg:justify-start">
{user && (
Expand Down

0 comments on commit 859b7c1

Please sign in to comment.