feat(21-03): rewire card click handlers to navigate to detail pages
- ItemCard navigates to /items/$itemId instead of opening edit panel - CandidateCard navigates to /threads/$threadId/candidates/$candidateId - CandidateListItem navigates to candidate detail page - CatalogSearchOverlay cards navigate to /global-items/$globalItemId - Add button on catalog cards uses stopPropagation to prevent navigation
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { useFormatters } from "../hooks/useFormatters";
|
||||
import type { CandidateDelta } from "../hooks/useImpactDeltas";
|
||||
import { LucideIcon } from "../lib/iconData";
|
||||
@@ -46,7 +47,7 @@ export function CandidateCard({
|
||||
delta,
|
||||
}: CandidateCardProps) {
|
||||
const { weight, price } = useFormatters();
|
||||
const openCandidateEditPanel = useUIStore((s) => s.openCandidateEditPanel);
|
||||
const navigate = useNavigate();
|
||||
const openConfirmDeleteCandidate = useUIStore(
|
||||
(s) => s.openConfirmDeleteCandidate,
|
||||
);
|
||||
@@ -56,7 +57,12 @@ export function CandidateCard({
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openCandidateEditPanel(id)}
|
||||
onClick={() =>
|
||||
navigate({
|
||||
to: "/threads/$threadId/candidates/$candidateId",
|
||||
params: { threadId: String(threadId), candidateId: String(id) },
|
||||
})
|
||||
}
|
||||
className="relative w-full text-left bg-white rounded-xl border border-gray-100 hover:border-gray-200 hover:shadow-sm transition-all overflow-hidden group"
|
||||
>
|
||||
{/* Hover-reveal action buttons */}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { Reorder } from "framer-motion";
|
||||
import { useRef } from "react";
|
||||
import { useFormatters } from "../hooks/useFormatters";
|
||||
@@ -60,7 +61,7 @@ export function CandidateListItem({
|
||||
}: CandidateListItemProps) {
|
||||
const isDragging = useRef(false);
|
||||
const { weight, price } = useFormatters();
|
||||
const openCandidateEditPanel = useUIStore((s) => s.openCandidateEditPanel);
|
||||
const navigate = useNavigate();
|
||||
const openConfirmDeleteCandidate = useUIStore(
|
||||
(s) => s.openConfirmDeleteCandidate,
|
||||
);
|
||||
@@ -104,7 +105,13 @@ export function CandidateListItem({
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (isDragging.current) return;
|
||||
openCandidateEditPanel(candidate.id);
|
||||
navigate({
|
||||
to: "/threads/$threadId/candidates/$candidateId",
|
||||
params: {
|
||||
threadId: String(candidate.threadId),
|
||||
candidateId: String(candidate.id),
|
||||
},
|
||||
});
|
||||
}}
|
||||
className="flex-1 min-w-0 text-left"
|
||||
>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
@@ -7,6 +8,7 @@ import { useTags } from "../hooks/useTags";
|
||||
import { useUIStore } from "../stores/uiStore";
|
||||
|
||||
export function CatalogSearchOverlay() {
|
||||
const navigate = useNavigate();
|
||||
const catalogSearchOpen = useUIStore((s) => s.catalogSearchOpen);
|
||||
const catalogSearchMode = useUIStore((s) => s.catalogSearchMode);
|
||||
const closeCatalogSearch = useUIStore((s) => s.closeCatalogSearch);
|
||||
@@ -138,7 +140,25 @@ export function CatalogSearchOverlay() {
|
||||
{items.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="bg-white rounded-xl border border-gray-100 overflow-hidden"
|
||||
className="bg-white rounded-xl border border-gray-100 overflow-hidden cursor-pointer hover:border-gray-200 hover:shadow-sm transition-all"
|
||||
onClick={() => {
|
||||
closeCatalogSearch();
|
||||
navigate({
|
||||
to: "/global-items/$globalItemId",
|
||||
params: { globalItemId: String(item.id) },
|
||||
});
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
closeCatalogSearch();
|
||||
navigate({
|
||||
to: "/global-items/$globalItemId",
|
||||
params: { globalItemId: String(item.id) },
|
||||
});
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className="aspect-[4/3] bg-gray-50">
|
||||
{item.imageUrl ? (
|
||||
@@ -191,7 +211,10 @@ export function CatalogSearchOverlay() {
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleAddStub}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleAddStub();
|
||||
}}
|
||||
className="bg-gray-700 text-white rounded-lg px-3 py-1.5 text-xs font-medium hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
Add
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { useFormatters } from "../hooks/useFormatters";
|
||||
import { useDuplicateItem } from "../hooks/useItems";
|
||||
import { LucideIcon } from "../lib/iconData";
|
||||
@@ -36,14 +37,16 @@ export function ItemCard({
|
||||
onClassificationCycle,
|
||||
}: ItemCardProps) {
|
||||
const { weight, price } = useFormatters();
|
||||
const openEditPanel = useUIStore((s) => s.openEditPanel);
|
||||
const navigate = useNavigate();
|
||||
const openExternalLink = useUIStore((s) => s.openExternalLink);
|
||||
const duplicateItem = useDuplicateItem();
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openEditPanel(id)}
|
||||
onClick={() =>
|
||||
navigate({ to: "/items/$itemId", params: { itemId: String(id) } })
|
||||
}
|
||||
className="relative w-full text-left bg-white rounded-xl border border-gray-100 hover:border-gray-200 hover:shadow-sm transition-all overflow-hidden group"
|
||||
>
|
||||
{!onRemove && (
|
||||
@@ -54,7 +57,10 @@ export function ItemCard({
|
||||
e.stopPropagation();
|
||||
duplicateItem.mutate(id, {
|
||||
onSuccess: (newItem) => {
|
||||
openEditPanel(newItem.id);
|
||||
navigate({
|
||||
to: "/items/$itemId",
|
||||
params: { itemId: String(newItem.id) },
|
||||
});
|
||||
},
|
||||
});
|
||||
}}
|
||||
@@ -63,7 +69,10 @@ export function ItemCard({
|
||||
e.stopPropagation();
|
||||
duplicateItem.mutate(id, {
|
||||
onSuccess: (newItem) => {
|
||||
openEditPanel(newItem.id);
|
||||
navigate({
|
||||
to: "/items/$itemId",
|
||||
params: { itemId: String(newItem.id) },
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user