-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathpurchaseSection.tsx
318 lines (287 loc) · 10.6 KB
/
purchaseSection.tsx
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
"use client";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useToast } from "@/components/ui/use-toast";
import { User } from "@/db/schema";
import {
addItemToWatchList,
getUser,
isUserWatchingItem,
purchaseItem,
removeItemFromWatchList,
unlistItem,
} from "@/db/utils";
import { CartItem } from "@/lib/cart";
import { UserStatus } from "@/lib/types";
import { cn } from "@/lib/utils";
import { ShoppingCartIcon } from "lucide-react";
import { getSession } from "next-auth/react";
import { useEffect, useState } from "react";
/*
This is the purchase section of the item page. It is loaded on the client side and is responsible
for handling the purchase of the item.
*/
export default function PurchaseSection({
itemId, // The id of the item
sellerUsername, // The username of the seller of the item
available, // The quantity of the item available for purchase
listed, // Whether the item is listed (1) or not (0).
itemTitle, // The title of the item
itemImage, // The image of the item
itemPrice, // The price of the item
}: {
itemId: string;
sellerUsername: string;
listed: 0 | 1;
available: number;
itemTitle: string;
itemImage: string;
itemPrice: number;
}) {
const { toast } = useToast(); // The toast hook
const [user, setUser] = useState<User | null>(null); // The current user
const [userStatus, setUserStatus] = useState(UserStatus.Visitor); // The status of the current user (seller, buyer, or visitor)
const [quantity, setQuantity] = useState<string>("1"); // The quantity of the item to be purchased
const [loading, setLoading] = useState(false); // Whether the page is loading
const [error, setError] = useState(""); // The error message to be displayed
const [success, setSuccess] = useState(""); // The success message to be displayed
const [isWatched, setIsWatched] = useState(false); // Whether the item is in the user's watch list
/*
On page load, get the current user and update the state variables that are dependent on the user.
*/
useEffect(() => {
/*
TODO: Update the following state variables:
- user
- userStatus
- isWatched
HINT: Get the logged in user's session and then get the user from the database to update the
user state variable. Then, check if the user is the seller of the item to update the
userStatus state variable. Finally, check if the user is watching the item to update the
isWatched state variable.
*/
}, []);
/*
Purchases the item immediately.
*/
const onBuyNow = async () => {
/*
TODO: Add a check to see if the user is logged in and is the buyer of the item
If not, return
*/
/*
TODO: Set loading to true
*/
/*
TODO: Parse the quantity state variable to ensure that it is a valid integer
If not, set error to "Invalid quantity!", set loading to false, and return
*/
/*
TODO: Call the purchaseItem function
*/
/*
TODO: Set success to "Purchase successful!"
*/
/*
TODO: Set loading to false
*/
/*
TODO: Redirect the user to the purchases tab of their profile page
*/
};
/*
Adds the item to the user's cart.
*/
const onAddToCart = async () => {
/*
TODO: Add a check to see if the user is logged in and is the buyer of the item
If not, return
*/
/*
TODO: Retrieve the cart from local storage and parse it into a CartItem array
*/
/*
TODO: Parse the quantity state variable to ensure that it is a valid integer
If not, set error to "Invalid quantity!", set loading to false, and return
*/
/*
TODO: If the item is already in the cart, increment the quantity of the item in the cart,
otherwise, add the item to the cart
*/
/*
TODO: Stringify the cart and set it in local storage
*/
/*
TODO: Dispatches an event to update the cart icon in the navbar and displays a toast
HINT: Dispatch an event with the name "cartUpdated"
*/
};
/*
Unlists the item, making it unavailable for purchase. This can only be done by the seller.
*/
const onRemoveListing = async () => {
/*
TODO: Add a check to see if the user is logged in and is the seller of the item
If not, return
*/
/*
TODO: Set loading to true
*/
/*
TODO: Call the unlistItem function
*/
/*
TODO: Set success to "Listing removed!"
*/
/*
TODO: Set loading to false
*/
/*
TODO: Redirect the user to their profile page
*/
};
/*
TODO: Render a different UI depending on the user's status (seller, buyer, or visitor)
- Seller: If the user is the seller of the item, display a button to remove the listing. Use the
UI provided below:
```
<Card className="items-center p-6 flex flex-col gap-3 w-3/12 sticky top-6">
<Button
disabled={loading || listed == 0}
className="w-full"
variant="destructive"
onClick={onRemoveListing}
>
{loading
? "Loading..."
: success
? success
: error
? error
: listed == 1
? "Remove listing"
: "Listing removed"}
</Button>
</Card>
```
- Buyer: If the user is the buyer of the item, display buttons to buy the item, add it to the
cart, and add it to the watch list. Use the UI provided below:
```
<Card className="items-center p-6 flex flex-col gap-3 w-3/12 sticky top-6">
<div className="flex flex-col items-center w-full gap-4">
<div className="flex justify-center flex-col items-start w-full">
<p className="text-3xl font-semibold">${itemPrice}</p>
<p
className={cn(
`text-xl font-semibold`,
available === 0 ? "text-red-600" : "text-green-600"
)}
>
{available === 0 ? "Out of Stock" : "In Stock"}
</p>
</div>
<div className="w-full flex flex-row items-center justify-start gap-4">
<Label htmlFor="username" className="text-center text-lg">
Qty:
</Label>
<Input
id="username"
value={quantity}
onChange={(e) => {
setQuantity(e.target.value);
}}
type="number"
className={
"w-[90px] bg-white flex flex-row items-center border border-black/25 rounded py-2 px-3 space-x-2" +
`${
isNaN(parseInt(quantity)) || parseInt(quantity) > available
? " text-red-500"
: ""
}`
}
/>
</div>
<Button
disabled={loading || available == 0 || listed == 0}
className="w-full font-medium bg-[#FFA41C] text-black hover:bg-[#FFB41C]"
onClick={onBuyNow}
>
{loading
? "Loading..."
: success
? success
: error
? error
: available == 0
? "Out of stock"
: listed == 1
? "Buy now"
: "Item not available"}
</Button>
<Button
disabled={loading || available == 0 || listed == 0}
className="w-full font-medium bg-[#FFD813] text-black hover:bg-[#FFE813]"
onClick={onAddToCart}
>
<ShoppingCartIcon className="w-4 h-4 mr-2" />
{loading
? "Loading..."
: success
? success
: error
? error
: available == 0
? "Out of stock"
: listed == 1
? "Add to cart"
: "Item not available"}
</Button>
<div className="py-2 w-full">
<div className="bg-black/50 w-full h-px" />
</div>
{isWatched ? (
<Button
disabled={loading || available == 0 || listed == 0}
variant="outline"
className="w-full font-medium rounded-lg text-black "
onClick={() => {
if (!user) {
return;
}
removeItemFromWatchList(user.username, itemId);
setIsWatched(false);
}}
>
Remove from Watch List
</Button>
) : (
<Button
disabled={loading || available == 0 || listed == 0}
className="w-full font-medium bg-white border border-black/50 py-3 rounded-full text-black hover:bg-white"
onClick={() => {
if (!user) {
return;
}
addItemToWatchList(user.username, itemId);
setIsWatched(true);
}}
>
Add to Watch List
</Button>
)}
</div>
</Card>
```
- Visitor: If the user is not logged in, display a button telling them to log in. Use the UI
provided below:
```
<Card className="items-center p-6 flex flex-col gap-3 w-3/12 sticky top-6">
<Button disabled variant="outline" className="w-full">
Log in to purchase
</Button>
</Card>
```
*/
}