stay_commerce-frontend 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/builds/bundle.css +8665 -6069
- data/app/assets/builds/bundle.css.map +3 -3
- data/app/assets/builds/bundle.js +37877 -27557
- data/app/assets/builds/bundle.js.map +4 -4
- data/app/assets/builds/styles.css +6328 -5031
- data/app/assets/builds/styles.css.map +3 -3
- data/app/javascript/react/components/Accountpage/AccountInfo.jsx +2 -1
- data/app/javascript/react/components/AddNewProperty/CommonLayout.jsx +0 -2
- data/app/javascript/react/components/AddNewProperty/Description.jsx +51 -52
- data/app/javascript/react/components/AddNewProperty/Details.jsx +212 -129
- data/app/javascript/react/components/AddNewProperty/Images.jsx +122 -45
- data/app/javascript/react/components/AddNewProperty/Location.jsx +21 -14
- data/app/javascript/react/components/AddNewProperty/Room.jsx +639 -548
- data/app/javascript/react/components/AvatarDropdown/AvatarDropDown.jsx +9 -1
- data/app/javascript/react/components/FacilitiesSection/Facilities.jsx +18 -0
- data/app/javascript/react/components/FixedNavbar/FixedNav.jsx +20 -14
- data/app/javascript/react/components/HeroSectionDesign/BookingForm.jsx +136 -88
- data/app/javascript/react/components/HeroSectionDesign/MyPropertiesListing.jsx +79 -69
- data/app/javascript/react/components/Layout/Layout.js +8 -1
- data/app/javascript/react/components/Listing-stay-Detail/ApartmentCard.jsx +3 -3
- data/app/javascript/react/components/Listing-stay-Detail/BookingModal.jsx +167 -122
- data/app/javascript/react/components/Listing-stay-Detail/CardManager.jsx +285 -0
- data/app/javascript/react/components/Listing-stay-Detail/CheckoutForm.jsx +147 -84
- data/app/javascript/react/components/Listing-stay-Detail/ListingStayDetailPage.jsx +1 -7
- data/app/javascript/react/components/Listing-stay-Detail/PropertiesPage.jsx +464 -0
- data/app/javascript/react/components/MobileNav/MobileMenu.jsx +1 -4
- data/app/javascript/react/components/PropertyListing/MyProperties.jsx +45 -44
- data/app/javascript/react/components/PropertyListing/StayBooking/BookingDetails.jsx +4 -4
- data/app/javascript/react/components/PropertyListing/StayBooking/MyBooking.jsx +41 -29
- data/app/javascript/react/components/StayCard/StayCard.jsx +5 -3
- data/app/javascript/react/packs/index.jsx +1 -0
- data/app/javascript/react/packs/routes/Route.jsx +18 -1
- data/app/javascript/react/pages/Home.jsx +6 -4
- data/app/javascript/react/redux/slices/PropertySlice/PropertySlice.jsx +21 -21
- data/app/javascript/react/redux/slices/PropertySlice/Searchslice.jsx +53 -6
- data/app/javascript/react/redux/slices/UserSlice/UserSlice.jsx +1 -0
- data/app/javascript/react/shared/Avatar/Avatar.jsx +5 -8
- data/app/javascript/react/shared/Button/SecondryButton.jsx +9 -0
- data/app/javascript/react/shared/Loader.jsx +13 -0
- data/app/javascript/react/shared/Pagination.jsx +53 -0
- data/app/javascript/react/shared/Schema/FormSchema +143 -0
- data/app/javascript/react/styles/BookingDetails.scss +1 -0
- data/app/javascript/react/styles/CardManager.scss +608 -0
- data/app/javascript/react/styles/Loader.scss +30 -0
- data/app/javascript/react/styles/Pagination.scss +33 -0
- data/app/javascript/react/styles/PropertiesPage.scss +0 -4
- data/app/javascript/react/styles/RenderSection.scss +1 -0
- data/app/javascript/react/styles/accountpage.scss +3 -0
- data/app/javascript/react/styles/application.scss +13 -1
- data/app/javascript/react/styles/bookingform.scss +56 -28
- data/app/javascript/react/styles/buttonSecondry.scss +24 -0
- data/app/javascript/react/styles/checkbox.scss +34 -35
- data/app/javascript/react/styles/commonlayout.scss +7 -2
- data/app/javascript/react/styles/commonpage.scss +5 -1
- data/app/javascript/react/styles/description.scss +3 -0
- data/app/javascript/react/styles/facilities.scss +2 -1
- data/app/javascript/react/styles/fixednavbar.scss +8 -0
- data/app/javascript/react/styles/listingstaydetailpage.scss +5 -0
- data/app/javascript/react/styles/mobilemenu.scss +0 -1
- data/app/javascript/react/styles/mybooking.scss +20 -0
- data/app/javascript/react/styles/myproperty.scss +26 -0
- data/app/javascript/react/styles/propertydetailscard.scss +265 -267
- data/app/javascript/react/styles/react-datepicker/react-datepicker.css +869 -0
- data/app/javascript/react/styles/room.scss +13 -8
- data/app/javascript/react/utils/helpers/ToastErros.js +12 -0
- data/db/migrate/20250627101451_add_role_to_stay_users.rb +5 -0
- data/lib/stay_commerce/frontend/version.rb +1 -1
- metadata +15 -5
- data/app/javascript/react/components/HeroSectionDesign/PropertiesPage.jsx +0 -122
- data/app/javascript/react/shared/DateField/CustomDatePicker.jsx +0 -69
- data/app/javascript/react/styles/customdatepicker.scss +0 -120
@@ -5,6 +5,7 @@ import { useFormik } from "formik";
|
|
5
5
|
import ButtonPrimary from "../../shared/Button/ButtonPrimary";
|
6
6
|
import { currencySymbol } from "../../shared/CurrencySymbol";
|
7
7
|
import Badge from "../../shared/Badge/Badge";
|
8
|
+
import DatePicker from "react-datepicker";
|
8
9
|
|
9
10
|
const BookingModal = ({
|
10
11
|
isOpen,
|
@@ -13,10 +14,26 @@ const BookingModal = ({
|
|
13
14
|
propertyData,
|
14
15
|
onSubmit,
|
15
16
|
isLoading,
|
17
|
+
error: externalError,
|
16
18
|
}) => {
|
17
19
|
const [error, setError] = useState("");
|
18
20
|
const [isButtonDisabled, setIsButtonDisabled] = useState(true);
|
21
|
+
const bookedDateRanges = room?.booked_dates || [];
|
22
|
+
const excludedDates = bookedDateRanges.flatMap(([start, end]) => {
|
23
|
+
const startDate = moment(start);
|
24
|
+
const endDate = moment(end);
|
25
|
+
const dates = [];
|
19
26
|
|
27
|
+
for (
|
28
|
+
let m = startDate.clone();
|
29
|
+
m.isSameOrBefore(endDate);
|
30
|
+
m.add(1, "day")
|
31
|
+
) {
|
32
|
+
dates.push(m.toDate());
|
33
|
+
}
|
34
|
+
|
35
|
+
return dates;
|
36
|
+
});
|
20
37
|
const formik = useFormik({
|
21
38
|
initialValues: {
|
22
39
|
number_of_guests: null,
|
@@ -31,6 +48,14 @@ const BookingModal = ({
|
|
31
48
|
},
|
32
49
|
});
|
33
50
|
|
51
|
+
// Update error state when external error changes
|
52
|
+
useEffect(() => {
|
53
|
+
if (externalError) {
|
54
|
+
setError(externalError);
|
55
|
+
}
|
56
|
+
}, [externalError]);
|
57
|
+
|
58
|
+
// Update form validation
|
34
59
|
useEffect(() => {
|
35
60
|
const { booking_start, booking_end, number_of_guests } = formik.values;
|
36
61
|
if (booking_start && booking_end && number_of_guests) {
|
@@ -40,12 +65,44 @@ const BookingModal = ({
|
|
40
65
|
}
|
41
66
|
}, [formik.values]);
|
42
67
|
|
68
|
+
// Reset form when room changes
|
69
|
+
useEffect(() => {
|
70
|
+
if (room) {
|
71
|
+
formik.setValues({
|
72
|
+
number_of_guests: null,
|
73
|
+
booking_start: null,
|
74
|
+
booking_end: null,
|
75
|
+
room_id: room.id,
|
76
|
+
price_per_month: room.price_per_month,
|
77
|
+
});
|
78
|
+
setError("");
|
79
|
+
}
|
80
|
+
}, [room]);
|
81
|
+
|
43
82
|
const handleBackdropClick = (e) => {
|
44
83
|
if (e.target === e.currentTarget) {
|
45
84
|
onClose();
|
46
85
|
}
|
47
86
|
};
|
48
87
|
|
88
|
+
const handleFormSubmit = (e) => {
|
89
|
+
e.preventDefault();
|
90
|
+
if (
|
91
|
+
!formik.values.booking_start ||
|
92
|
+
!formik.values.booking_end ||
|
93
|
+
!formik.values.number_of_guests
|
94
|
+
) {
|
95
|
+
setError("Please fill in all required fields");
|
96
|
+
return;
|
97
|
+
}
|
98
|
+
|
99
|
+
// Clear any existing errors
|
100
|
+
setError("");
|
101
|
+
|
102
|
+
// Call the submit handler
|
103
|
+
formik.handleSubmit();
|
104
|
+
};
|
105
|
+
|
49
106
|
if (!isOpen || !room) return null;
|
50
107
|
|
51
108
|
return (
|
@@ -99,10 +156,23 @@ const BookingModal = ({
|
|
99
156
|
>
|
100
157
|
<X size={20} />
|
101
158
|
</button>
|
159
|
+
|
102
160
|
<div style={{ marginBottom: "24px", paddingRight: "40px" }}>
|
103
161
|
<h2 style={{ margin: 0, fontSize: "24px", fontWeight: "600" }}>
|
104
162
|
{room?.name}
|
105
163
|
</h2>
|
164
|
+
{/* Display Property Information */}
|
165
|
+
{propertyData && (
|
166
|
+
<p
|
167
|
+
style={{
|
168
|
+
margin: "8px 0 0 0",
|
169
|
+
color: "#6b7280",
|
170
|
+
fontSize: "14px",
|
171
|
+
}}
|
172
|
+
>
|
173
|
+
Property: {propertyData.title}
|
174
|
+
</p>
|
175
|
+
)}
|
106
176
|
</div>
|
107
177
|
|
108
178
|
<div className="listingSectionSidebar__wrap">
|
@@ -133,7 +203,7 @@ const BookingModal = ({
|
|
133
203
|
</span>
|
134
204
|
</div>
|
135
205
|
|
136
|
-
<form onSubmit={
|
206
|
+
<form onSubmit={handleFormSubmit}>
|
137
207
|
<div
|
138
208
|
className="form-content"
|
139
209
|
style={{ display: "flex", flexDirection: "column", gap: "10px" }}
|
@@ -149,21 +219,17 @@ const BookingModal = ({
|
|
149
219
|
>
|
150
220
|
Availability Start Date
|
151
221
|
</label>
|
152
|
-
<
|
222
|
+
<DatePicker
|
153
223
|
id={`booking_start_${room?.id}`}
|
154
|
-
type="date"
|
155
224
|
className="form-input-large"
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
"YYYY-MM-DD"
|
161
|
-
)
|
162
|
-
: ""
|
225
|
+
selected={
|
226
|
+
formik.values.booking_start
|
227
|
+
? new Date(formik.values.booking_start)
|
228
|
+
: null
|
163
229
|
}
|
164
|
-
onChange={(
|
230
|
+
onChange={(date) => {
|
165
231
|
setError("");
|
166
|
-
formik.setFieldValue("booking_start",
|
232
|
+
formik.setFieldValue("booking_start", date);
|
167
233
|
formik.setFieldValue("booking_end", null);
|
168
234
|
formik.setFieldValue("number_of_guests", null);
|
169
235
|
formik.setFieldValue("room_id", room?.id);
|
@@ -172,10 +238,11 @@ const BookingModal = ({
|
|
172
238
|
room?.price_per_month
|
173
239
|
);
|
174
240
|
}}
|
175
|
-
|
241
|
+
disabled={room?.to_book === false}
|
242
|
+
minDate={
|
176
243
|
room?.to_book === true
|
177
|
-
?
|
178
|
-
?
|
244
|
+
? room?.next_available_date
|
245
|
+
? new Date(room.next_available_date)
|
179
246
|
: moment(
|
180
247
|
moment(
|
181
248
|
room?.booking_start ??
|
@@ -184,7 +251,7 @@ const BookingModal = ({
|
|
184
251
|
? room?.booking_start ??
|
185
252
|
propertyData?.availability_start
|
186
253
|
: new Date()
|
187
|
-
).
|
254
|
+
).toDate()
|
188
255
|
: moment(
|
189
256
|
moment(
|
190
257
|
room?.booking_start ??
|
@@ -193,24 +260,19 @@ const BookingModal = ({
|
|
193
260
|
? room?.booking_start ??
|
194
261
|
propertyData?.availability_start
|
195
262
|
: new Date()
|
196
|
-
).
|
263
|
+
).toDate()
|
197
264
|
}
|
198
|
-
|
265
|
+
maxDate={
|
199
266
|
room?.booking_end
|
200
|
-
?
|
267
|
+
? new Date(room.booking_end)
|
201
268
|
: propertyData?.availability_end
|
202
|
-
?
|
203
|
-
"YYYY-MM-DD"
|
204
|
-
)
|
269
|
+
? new Date(propertyData.availability_end)
|
205
270
|
: undefined
|
206
271
|
}
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
borderRadius: "8px",
|
212
|
-
fontSize: "16px",
|
213
|
-
}}
|
272
|
+
excludeDates={excludedDates}
|
273
|
+
placeholderText="Select start date"
|
274
|
+
dateFormat="yyyy-MM-dd"
|
275
|
+
isClearable
|
214
276
|
/>
|
215
277
|
</div>
|
216
278
|
|
@@ -225,42 +287,31 @@ const BookingModal = ({
|
|
225
287
|
>
|
226
288
|
Availability End Date
|
227
289
|
</label>
|
228
|
-
<
|
229
|
-
type="date"
|
290
|
+
<DatePicker
|
230
291
|
id={`booking_end_${room?.id}`}
|
231
292
|
className="form-input-large"
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
: ""
|
293
|
+
selected={
|
294
|
+
formik.values.booking_end
|
295
|
+
? new Date(formik.values.booking_end)
|
296
|
+
: null
|
237
297
|
}
|
238
|
-
onChange={(
|
298
|
+
onChange={(date) => {
|
239
299
|
setError("");
|
240
300
|
formik.setFieldValue("room_id", room?.id);
|
241
301
|
formik.setFieldValue(
|
242
302
|
"price_per_month",
|
243
303
|
room?.price_per_month
|
244
304
|
);
|
245
|
-
formik.setFieldValue("booking_end",
|
305
|
+
formik.setFieldValue("booking_end", date);
|
246
306
|
}}
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
.
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
: moment(
|
256
|
-
moment(
|
257
|
-
room?.booking_start ??
|
258
|
-
propertyData?.availability_start
|
259
|
-
).isAfter(moment())
|
260
|
-
? room?.booking_start ??
|
261
|
-
propertyData?.availability_start
|
262
|
-
: new Date()
|
263
|
-
).format("YYYY-MM-DD")
|
307
|
+
disabled={room?.to_book === false}
|
308
|
+
minDate={
|
309
|
+
formik.values.booking_start
|
310
|
+
? moment(formik.values.booking_start)
|
311
|
+
.add(1, "days")
|
312
|
+
.toDate()
|
313
|
+
: room?.next_available_date
|
314
|
+
? new Date(room.next_available_date)
|
264
315
|
: moment(
|
265
316
|
moment(
|
266
317
|
room?.booking_start ??
|
@@ -269,36 +320,22 @@ const BookingModal = ({
|
|
269
320
|
? room?.booking_start ??
|
270
321
|
propertyData?.availability_start
|
271
322
|
: new Date()
|
272
|
-
).
|
323
|
+
).toDate()
|
273
324
|
}
|
274
|
-
|
325
|
+
maxDate={
|
275
326
|
room?.booking_end
|
276
|
-
?
|
327
|
+
? new Date(room.booking_end)
|
277
328
|
: propertyData?.availability_end
|
278
|
-
?
|
279
|
-
"YYYY-MM-DD"
|
280
|
-
)
|
329
|
+
? new Date(propertyData.availability_end)
|
281
330
|
: undefined
|
282
331
|
}
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
borderRadius: "8px",
|
288
|
-
fontSize: "16px",
|
289
|
-
}}
|
332
|
+
excludeDates={excludedDates}
|
333
|
+
placeholderText="Select end date"
|
334
|
+
dateFormat="yyyy-MM-dd"
|
335
|
+
isClearable
|
290
336
|
/>
|
291
337
|
</div>
|
292
338
|
|
293
|
-
{error && (
|
294
|
-
<span
|
295
|
-
className="error-text"
|
296
|
-
style={{ color: "#ef4444", fontSize: "14px" }}
|
297
|
-
>
|
298
|
-
{error}
|
299
|
-
</span>
|
300
|
-
)}
|
301
|
-
|
302
339
|
<div className="form-group">
|
303
340
|
<label
|
304
341
|
htmlFor={`number_of_guests_${room?.id}`}
|
@@ -323,14 +360,6 @@ const BookingModal = ({
|
|
323
360
|
!formik.values.booking_end ||
|
324
361
|
room?.to_book === false
|
325
362
|
}
|
326
|
-
style={{
|
327
|
-
width: "100%",
|
328
|
-
padding: "12px",
|
329
|
-
border: "1px solid #d1d5db",
|
330
|
-
borderRadius: "8px",
|
331
|
-
fontSize: "16px",
|
332
|
-
backgroundColor: "white",
|
333
|
-
}}
|
334
363
|
>
|
335
364
|
<option value="" disabled>
|
336
365
|
Select number of guests
|
@@ -342,53 +371,69 @@ const BookingModal = ({
|
|
342
371
|
))}
|
343
372
|
</select>
|
344
373
|
</div>
|
374
|
+
|
375
|
+
{error && (
|
376
|
+
<div
|
377
|
+
className="error-text"
|
378
|
+
style={{
|
379
|
+
color: "#ef4444",
|
380
|
+
fontSize: "14px",
|
381
|
+
padding: "8px",
|
382
|
+
backgroundColor: "#fef2f2",
|
383
|
+
border: "1px solid #fecaca",
|
384
|
+
borderRadius: "4px",
|
385
|
+
}}
|
386
|
+
>
|
387
|
+
{error}
|
388
|
+
</div>
|
389
|
+
)}
|
345
390
|
</div>
|
346
|
-
</form>
|
347
391
|
|
348
|
-
<div
|
349
|
-
className="price-breakdown"
|
350
|
-
style={{
|
351
|
-
marginTop: "24px",
|
352
|
-
paddingTop: "15px",
|
353
|
-
borderTop: "1px solid #e5e7eb",
|
354
|
-
}}
|
355
|
-
>
|
356
392
|
<div
|
357
|
-
className="price-
|
393
|
+
className="price-breakdown"
|
358
394
|
style={{
|
359
|
-
|
360
|
-
|
361
|
-
alignItems: "center",
|
395
|
+
paddingTop: "15px",
|
396
|
+
borderTop: "1px solid #e5e7eb",
|
362
397
|
}}
|
363
398
|
>
|
364
|
-
<div
|
365
|
-
|
399
|
+
<div
|
400
|
+
className="price-row"
|
401
|
+
style={{
|
402
|
+
display: "flex",
|
403
|
+
justifyContent: "space-between",
|
404
|
+
alignItems: "center",
|
405
|
+
}}
|
406
|
+
>
|
407
|
+
<div className="info-icon">
|
408
|
+
<span style={{ fontWeight: "500" }}>Amount</span>
|
409
|
+
</div>
|
410
|
+
<span style={{ fontWeight: "600", fontSize: "18px" }}>
|
411
|
+
{`${currencySymbol()} ${
|
412
|
+
Number(room?.price_per_month)?.toFixed(2) || 0
|
413
|
+
}`}
|
414
|
+
</span>
|
366
415
|
</div>
|
367
|
-
<span style={{ fontWeight: "600", fontSize: "18px" }}>
|
368
|
-
{`${currencySymbol()} ${
|
369
|
-
Number(room?.price_per_month)?.toFixed(2) || 0
|
370
|
-
}`}
|
371
|
-
</span>
|
372
416
|
</div>
|
373
|
-
</div>
|
374
417
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
>
|
379
|
-
<ButtonPrimary
|
380
|
-
disabled={
|
381
|
-
isButtonDisabled ||
|
382
|
-
room?.status === "inactive" ||
|
383
|
-
room?.to_book === false
|
384
|
-
}
|
385
|
-
onClick={formik.handleSubmit}
|
386
|
-
loading={isLoading}
|
387
|
-
className="book-now-btn"
|
418
|
+
<div
|
419
|
+
className="button-group"
|
420
|
+
style={{ marginTop: "24px", width: "100%" }}
|
388
421
|
>
|
389
|
-
|
390
|
-
|
391
|
-
|
422
|
+
<ButtonPrimary
|
423
|
+
type="submit"
|
424
|
+
disabled={
|
425
|
+
isButtonDisabled ||
|
426
|
+
room?.status === "inactive" ||
|
427
|
+
room?.to_book === false ||
|
428
|
+
isLoading
|
429
|
+
}
|
430
|
+
loading={isLoading}
|
431
|
+
className="book-now-btn"
|
432
|
+
>
|
433
|
+
Book Now
|
434
|
+
</ButtonPrimary>
|
435
|
+
</div>
|
436
|
+
</form>
|
392
437
|
</div>
|
393
438
|
</div>
|
394
439
|
</div>
|