-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathListingDetail.tsx
More file actions
111 lines (103 loc) · 4.12 KB
/
ListingDetail.tsx
File metadata and controls
111 lines (103 loc) · 4.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"use client";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { addToUsersFavorites, deleteFromUsersFavorites } from "@/lib/actions";
import { Heart, Share } from "lucide-react";
import { Item, Sublet } from "@/lib/types";
import { ListingActions } from "@/components/listings/detail/ListingActions";
import { ListingImageGallery } from "@/components/listings/detail/ListingImageGallery";
import { ListingInfo } from "@/components/listings/detail/ListingInfo";
import { UserCard } from "@/components/listings/detail/UserCard";
import { BackButton } from "@/components/listings/detail/BackButton";
import { SubletMap } from "@/components/listings/detail/SubletMap";
interface Props {
listing: Item | Sublet;
initialIsFavorited: boolean;
}
export const ListingDetail = ({ listing, initialIsFavorited }: Props) => {
const listingType = listing.listing_type;
const priceLabel = listingType === "sublet" ? "/mo" : undefined;
const listingOwnerLabel = listingType === "item" ? "Seller" : "Owner";
const queryClient = useQueryClient();
const favoritesQuery = useQuery({
queryKey: ["favorite", listing.id],
queryFn: async () => initialIsFavorited,
initialData: initialIsFavorited,
staleTime: Infinity,
});
const isFavorited = favoritesQuery.data ?? false;
const toggleFavoriteMutation = useMutation({
meta: { suppressErrorToast: true }, // since it's noisy to show error toast on top of optimistic update
mutationFn: async (shouldFavorite: boolean) => {
if (shouldFavorite) {
await addToUsersFavorites(listing.id);
} else {
await deleteFromUsersFavorites(listing.id);
}
},
onMutate: async (shouldFavorite: boolean) => {
await queryClient.cancelQueries({ queryKey: ["favorite", listing.id] });
const previous = queryClient.getQueryData<boolean>(["favorite", listing.id]);
queryClient.setQueryData(["favorite", listing.id], shouldFavorite);
return { previous };
},
onError: (_error, _shouldFavorite, context) => {
if (context?.previous !== undefined) {
queryClient.setQueryData(["favorite", listing.id], context.previous);
}
},
});
const handleToggleFavorite = async () => {
toggleFavoriteMutation.mutate(!isFavorited);
};
const subletCoords =
listingType === "sublet" ? listing.additional_data : null;
const hasLocation =
subletCoords?.latitude != null && subletCoords?.longitude != null;
return (
<div className="mx-auto flex w-full max-w-[96rem] flex-col p-8 px-4 sm:px-12">
<div className="mb-4 flex items-center justify-between">
<BackButton />
<div className="flex items-center gap-3">
<Share className="h-5 w-5" />
<button
type="button"
className="cursor-pointer"
onClick={handleToggleFavorite}
aria-pressed={isFavorited}
aria-label={isFavorited ? "Remove from favorites" : "Add to favorites"}
>
<Heart className={isFavorited ? "h-5 w-5 fill-red-500 text-red-500" : "h-5 w-5"} />
</button>
</div>
</div>
<div className="grid grid-cols-1 gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]">
<ListingImageGallery images={listing.images} />
<div className="space-y-6">
<ListingInfo
title={listing.title}
price={listing.price}
description={listing.description}
priceLabel={priceLabel}
{...listing.additional_data}
/>
<UserCard user={listing.seller} label={listingOwnerLabel} />
<ListingActions
listingId={listing.id}
listingPrice={listing.price}
priceLabel={priceLabel}
listingOwnerLabel={listingOwnerLabel}
/>
{hasLocation && (
<div className="space-y-3">
<h2 className="text-lg font-semibold">{"Where you'll be living"}</h2>
<SubletMap
latitude={subletCoords.latitude!}
longitude={subletCoords.longitude!}
/>
</div>
)}
</div>
</div>
</div>
);
};