Skip to content

Commit 64e7522

Browse files
committed
fix: narrow thread effect deps; share ListingType with MapPin
- ListingRead: the thread-loading effect depended on the whole realListing object, so any parent re-render with a new listing identity (even with the same id/owner_id) refetched the thread. Depend on the specific fields the effect reads instead. - MapPin: drop the duplicated ListingPinType union and key the icon map on the shared ListingType. Adding a new listing type now surfaces as a compile error in MapPin, keeping the two from drifting out of sync. Made-with: Cursor
1 parent 5e205ac commit 64e7522

2 files changed

Lines changed: 18 additions & 16 deletions

File tree

src/components/ListingRead/ListingRead.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,18 @@ const ListingRead = memo(function Listing({
6464
const realListing =
6565
!isDemo && listing && !isDemoListing(listing) ? (listing as Listing) : null;
6666

67-
// Load existing thread if any (only if not in demo mode)
67+
// Load existing thread if any (only if not in demo mode). Depend on the
68+
// specific listing fields used inside the effect so a new `realListing`
69+
// object identity with the same id/owner doesn't refire the query.
70+
const listingId = realListing?.id;
71+
const listingOwnerId = realListing?.owner_id;
72+
const userId = user?.id;
6873
useEffect(() => {
69-
if (isDemo || !supabase || !user || !realListing) return;
74+
if (isDemo || !supabase || !userId || !listingId || !listingOwnerId) return;
7075

7176
// TODO: Should this only be called when the actual ListingChatDrawer is loaded?
7277
async function loadExistingThread() {
73-
if (!supabase || !user || !realListing) return;
78+
if (!supabase) return;
7479
const { data: thread, error } = await supabase
7580
.from("chat_threads_with_participants")
7681
.select(
@@ -80,9 +85,9 @@ const ListingRead = memo(function Listing({
8085
`
8186
)
8287
.match({
83-
listing_id: realListing.id,
84-
initiator_id: user.id,
85-
owner_id: realListing.owner_id,
88+
listing_id: listingId,
89+
initiator_id: userId,
90+
owner_id: listingOwnerId,
8691
})
8792
.maybeSingle();
8893

@@ -95,7 +100,7 @@ const ListingRead = memo(function Listing({
95100
}
96101

97102
loadExistingThread();
98-
}, [realListing?.id, user?.id, isDemo, supabase, realListing]);
103+
}, [listingId, listingOwnerId, userId, isDemo, supabase]);
99104

100105
const initialZoomLevel = 14;
101106

src/components/MapPin/MapPin.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import MapCommunityIcon from "../MapCommunityIcon";
33
import MapResidentialIcon from "../MapResidentialIcon";
44
import { styled } from "@pigment-css/react";
55

6-
type ListingPinType = "business" | "community" | "residential";
6+
import type { ListingType } from "@/types/listing";
77

88
type MapPinProps = {
99
selected?: boolean;
@@ -145,19 +145,16 @@ const SelectedPinIcon = (
145145

146146
const ICON = `M18.149 15.8139C18.2078 15.7251 18.2326 15.6533 18.2915 15.5646C19.3387 13.9878 20 12.0412 20 10C20 4.4 15.5 0 10 0C4.5 0 0 4.5 0 10C0 11.8662 0.522404 13.6453 1.40473 15.0937C1.52799 15.296 1.62851 15.5285 1.79602 15.696C1.79734 15.6974 1.79867 15.6987 1.8 15.7C1.90535 15.8054 1.94349 15.9666 2.02739 16.0897C2.18874 16.3264 2.36323 16.5632 2.6 16.8C4.5396 19.1126 7.70356 22.2044 9.18572 23.6258C9.64236 24.0637 10.3577 24.0638 10.8151 23.6266C12.2976 22.2097 15.4607 19.1376 17.4 16.9C17.5711 16.6433 17.8155 16.3866 18.0078 16.1299C18.07 16.0467 18.0918 15.9006 18.149 15.8139Z`;
147147

148-
const iconMap: Record<
149-
ListingPinType,
150-
React.ComponentType<{ size?: string }>
151-
> = {
148+
// Keyed on the shared `ListingType` union so adding a new type there becomes
149+
// a compile error here — prevents the two from drifting out of sync.
150+
const iconMap: Record<ListingType, React.ComponentType<{ size?: string }>> = {
152151
business: MapBusinessIcon as React.ComponentType<{ size?: string }>,
153152
community: MapCommunityIcon as React.ComponentType<{ size?: string }>,
154153
residential: MapResidentialIcon as React.ComponentType<{ size?: string }>,
155154
};
156155

157-
function isListingPinType(value: string | undefined): value is ListingPinType {
158-
return (
159-
value === "business" || value === "community" || value === "residential"
160-
);
156+
function isListingPinType(value: string | undefined): value is ListingType {
157+
return value !== undefined && value in iconMap;
161158
}
162159

163160
function MapPin({ selected = false, type }: MapPinProps) {

0 commit comments

Comments
 (0)