- {/* Overview + In the graph */}
- {/* Overview card */}
-
- Overview
-
- {(producer.description && producer.description.length > 0) && (
+
+
+
+ {producer.description ? (
-
Description
-
{producer.description}
+
Description
+
{producer.description}
- )}
- {producer.website && (
+ ) : null}
+ {producer.website ? (
- )}
- {producer.phone && (
+ ) : null}
+ {producer.phone ? (
- )}
- {producer.email && (
+ ) : null}
+ {producer.email ? (
- )}
+ ) : null}
-
+
- {/* In the graph card */}
-
- In the graph
-
- - {producer?.wines?.length ?? "—"} wines in Wine Graph
- - Located in # {producer.areas?.length ?? "0"} areas (AVA, AOC, etc)
- - Added to Wine Graph: {producer.createdAt ? new Date(producer.createdAt).getFullYear() : "—"}
+
+
+
+ - {producer?.wines?.length ?? 0} wines in Wine Graph
+ - Located in {producer.areas?.length ?? 0} areas (AVA, AOC, etc.)
+ - Added to Wine Graph: {producer.createdAt ? new Date(producer.createdAt).getFullYear() : "-"}
-
+
- {/* Wines + Retailers row */}
-
- {/* Wines list/table */}
-
- Wines from this producer
-
- {(!producer.wines || producer.wines.length === 0) ? (
-
No wines for this producer in Wine Graph yet.
- ) : (
-
-
-
-
- | Wine |
- Vintage |
- Varietal |
-
-
-
- {producer.wines.map((w) => (
-
- |
- {(w.slug && w.id) ? (
- {w.name}
- ) : (
- {w.name}
- )}
- |
- {w.vintage ?? "—"} |
- {w.varietal ?? "—"} |
-
- ))}
-
-
-
- )}
-
-
-
+
+
+ {!producer.wines || producer.wines.length === 0 ? (
+
+ ) : (
+ (w.slug && w.id)
+ ? {w.name}
+ : {w.name},
+ },
+ {id: "vintage", header: "Vintage", render: (w) => w.vintage ?? "-"},
+ {id: "varietal", header: "Varietal", render: (w) => w.varietal ?? "-"},
+ ]}
+ rows={producer.wines}
+ rowKey={(w) => w.slug || w.id || w.name}
+ />
+ )}
+
- {/* Data section */}
-
- Data
- Data completeness, corrections, and history will appear here.
-
+
+
+ Data completeness, corrections, and history will appear here.
+
)}
diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx
index 8d46f68..b6e7e7f 100644
--- a/src/pages/Profile.tsx
+++ b/src/pages/Profile.tsx
@@ -7,6 +7,7 @@ import {Send} from "lucide-react";
import {useNavigate} from "react-router-dom";
import GoogleProfile from "../components/GoogleProfile.tsx";
import {FullScreenSpinner} from "../components/FullScreenSpinner.tsx";
+import {Card, SectionTitle} from "../components/ui";
export const ProfilePage = () => {
const navigate = useNavigate();
@@ -33,18 +34,24 @@ export const ProfilePage = () => {
{!isAuthenticated ? (
{/* Left: Sign-in CTA */}
-
+
+
-
+
{/* Right: Roles overview (non-interactive pre-auth) */}
-
Sign in to choose your role and unlock the relevant tools.
+
Sign in to choose your role and unlock the relevant tools.
) : (
@@ -112,62 +119,65 @@ const RolePicker: React.FC<{ currentRole: Role; onChange: (r: Role) => void; dis
const handleConfirm = (e: React.FormEvent) => {
e.preventDefault();
if (canConfirm && pendingRole) {
- console.info("[role] confirm selection", {from: currentRole, to: pendingRole});
onChange(pendingRole);
}
};
return (
-
);
};
@@ -179,27 +189,31 @@ const RolesOverview = () => {
{title: "Enthusiast", desc: "Discover wines and retailers (read-only)."},
];
return (
-
-
Platform roles
-
Review roles, then pick one after you sign in.
+
+
{items.map((it) => (
- -
+
-
{it.title}
- {it.desc}
+ {it.desc}
))}
-
+
);
};
const CurrentRoleSummary: React.FC<{ role: Role }> = ({role}) => (
-
-
Current role
-
{role}
-
+
+
+ {role}
+
Role selection is part of initial setup. You can continue using Wine Graph with your current role.
-
-);
\ No newline at end of file
+
+);
diff --git a/src/pages/WinePage.tsx b/src/pages/WinePage.tsx
index 1981f2b..3e68bd9 100644
--- a/src/pages/WinePage.tsx
+++ b/src/pages/WinePage.tsx
@@ -4,15 +4,17 @@ import {useQuery} from "@apollo/client";
import {WINE_BY_ID_ENRICHED} from "../services/producer/wineGraph.ts";
import {producerClient} from "../services/apolloClient.ts";
import type {WineEnriched, WineProducer, WineRetailer} from "../users/producer/producer.ts";
-
-function SkeletonRow() {
- return
;
-}
+import {Card, DataTable, EmptyState, SectionTitle, StatePanel} from "../components/ui";
export default function WinePage() {
const {id} = useParams();
- const {data, loading, error, refetch} = useQuery(WINE_BY_ID_ENRICHED, {client: producerClient, variables: {id}, skip: !id});
+ const {data, loading, error, refetch} = useQuery(WINE_BY_ID_ENRICHED, {
+ client: producerClient,
+ variables: {id},
+ skip: !id,
+ });
+
const wine = data?.Wine?.enriched as WineEnriched | undefined;
const retailers = wine?.retailers as WineRetailer[] | undefined;
const producer = wine?.producer as WineProducer | undefined;
@@ -21,160 +23,118 @@ export default function WinePage() {
if (!wine) return "";
const parts: string[] = [];
if (wine.vintage) parts.push(String(wine.vintage));
- if (producer?.name) parts.push(producer.name);
+ if (wine.varietal) parts.push(wine.varietal);
if (wine.retailers?.length) parts.push(`${wine.retailers.length} retailers`);
return parts.join(" • ");
- }, [wine, producer?.name]);
+ }, [wine]);
return (
-
- {/* Breadcrumb */}
-