stay_commerce-frontend 0.1.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +8 -0
- data/app/assets/builds/404error-RVKQJ4S4.digested.jpg +0 -0
- data/app/assets/builds/Facebook-5HJUILVR.digested.svg +3 -0
- data/app/assets/builds/Google-CZ3UPVSC.digested.svg +6 -0
- data/app/assets/builds/application.js +95 -0
- data/app/assets/builds/application.js.map +7 -0
- data/app/assets/builds/beach-KAZW5GM3.digested.jpg +0 -0
- data/app/assets/builds/beach2-3ARC34NS.digested.jpg +0 -0
- data/app/assets/builds/beach3-PSTOH5FV.digested.jpg +0 -0
- data/app/assets/builds/beach4-PWNRPD3S.digested.jpg +0 -0
- data/app/assets/builds/beach5-SBOKKRHF.digested.jpg +0 -0
- data/app/assets/builds/beach6-SXZ5Y5AI.digested.jpg +0 -0
- data/app/assets/builds/beach7-FNBMFVKK.digested.jpg +0 -0
- data/app/assets/builds/beach8-TD7LTRQM.digested.jpg +0 -0
- data/app/assets/builds/bg-image-H7UGUMV2.digested.jpg +0 -0
- data/app/assets/builds/bgimage-DU3PCXKN.digested.jpg +0 -0
- data/app/assets/builds/bundle.css +30914 -0
- data/app/assets/builds/bundle.css.map +7 -0
- data/app/assets/builds/bundle.js +74569 -0
- data/app/assets/builds/bundle.js.map +7 -0
- data/app/assets/builds/hotel1-HGBXPKJK.digested.jpg +0 -0
- data/app/assets/builds/logo_updated-KQWAXLYL.digested.png +0 -0
- data/app/assets/builds/styles.css +6422 -0
- data/app/assets/builds/styles.css.map +7 -0
- data/app/assets/config/manifest.js +2 -0
- data/app/assets/images/favicon.ico +0 -0
- data/app/assets/images/stay_commerce/frontend/beach-666122_1280 (1).jpg +0 -0
- data/app/assets/images/stay_commerce/frontend/beach-666122_1280.jpg +0 -0
- data/app/assets/stylesheets/stay_commerce/frontend/application.css +15 -0
- data/app/controllers/stay_commerce/frontend/application_controller.rb +8 -0
- data/app/controllers/stay_commerce/frontend/welcome_controller.rb +6 -0
- data/app/helpers/stay_commerce/frontend/application_helper.rb +6 -0
- data/app/javascript/Images/404error.jpg +0 -0
- data/app/javascript/Images/Facebook.svg +3 -0
- data/app/javascript/Images/Google.svg +6 -0
- data/app/javascript/Images/beach-2245867_1280.jpg +0 -0
- data/app/javascript/Images/beach.jpg +0 -0
- data/app/javascript/Images/beach2.jpg +0 -0
- data/app/javascript/Images/beach3.jpg +0 -0
- data/app/javascript/Images/beach4.jpg +0 -0
- data/app/javascript/Images/beach5.jpg +0 -0
- data/app/javascript/Images/beach6.jpg +0 -0
- data/app/javascript/Images/beach7.jpg +0 -0
- data/app/javascript/Images/beach8.jpg +0 -0
- data/app/javascript/Images/bg-image.jpg +0 -0
- data/app/javascript/Images/bgimage.jpg +0 -0
- data/app/javascript/Images/blog-1.jpg +0 -0
- data/app/javascript/Images/gallery.png +0 -0
- data/app/javascript/Images/home 5.jpg +0 -0
- data/app/javascript/Images/home1.jpg +0 -0
- data/app/javascript/Images/home2.jpg +0 -0
- data/app/javascript/Images/home3.jpg +0 -0
- data/app/javascript/Images/home6.jpg +0 -0
- data/app/javascript/Images/hotel1.jpg +0 -0
- data/app/javascript/Images/room1.jpg +0 -0
- data/app/javascript/Images/room2.jpg +0 -0
- data/app/javascript/Images/room3.jpg +0 -0
- data/app/javascript/Images/room4.jpg +0 -0
- data/app/javascript/Images/wine-4520213_1280.jpg +0 -0
- data/app/javascript/application.js +1 -0
- data/app/javascript/react/Api/apiConstants.js +47 -0
- data/app/javascript/react/assets/beach-2245867_1280.jpg +0 -0
- data/app/javascript/react/assets/logo.png +0 -0
- data/app/javascript/react/assets/logo_updated.png +0 -0
- data/app/javascript/react/components/AboutUsPage/AboutPage.jsx +41 -0
- data/app/javascript/react/components/AboutusFront/About.jsx +37 -0
- data/app/javascript/react/components/Accommodation/Accommodation.jsx +32 -0
- data/app/javascript/react/components/Accommodation/NormalListing.jsx +50 -0
- data/app/javascript/react/components/Accommodation/SpecialListing.jsx +51 -0
- data/app/javascript/react/components/Accountpage/AccountInfo.jsx +217 -0
- data/app/javascript/react/components/Accountpage/AccountPage.jsx +27 -0
- data/app/javascript/react/components/Accountpage/CommonPage.jsx +24 -0
- data/app/javascript/react/components/AddNewProperty/CommonLayout.jsx +68 -0
- data/app/javascript/react/components/AddNewProperty/Description.jsx +229 -0
- data/app/javascript/react/components/AddNewProperty/Details.jsx +234 -0
- data/app/javascript/react/components/AddNewProperty/Images.jsx +196 -0
- data/app/javascript/react/components/AddNewProperty/Location.jsx +239 -0
- data/app/javascript/react/components/AddNewProperty/Room.jsx +1132 -0
- data/app/javascript/react/components/AvatarDropdown/AvatarDropDown.jsx +142 -0
- data/app/javascript/react/components/BlogDesign/BlogsLatest.jsx +67 -0
- data/app/javascript/react/components/ContactUs/Contact.jsx +89 -0
- data/app/javascript/react/components/FacilitiesSection/Facilities.jsx +66 -0
- data/app/javascript/react/components/FixedNavbar/FixedNav.jsx +88 -0
- data/app/javascript/react/components/ForgetPassword/ForgetPassword.jsx +103 -0
- data/app/javascript/react/components/Gallery/Gallery.jsx +164 -0
- data/app/javascript/react/components/GalleryModalLight/GalleryModalLight.jsx +35 -0
- data/app/javascript/react/components/GallerySlider/GallerySlider.jsx +58 -0
- data/app/javascript/react/components/Headers/PropertyCard.jsx +46 -0
- data/app/javascript/react/components/HeroSectionDesign/BookingForm.jsx +178 -0
- data/app/javascript/react/components/HeroSectionDesign/HeroSection.jsx +29 -0
- data/app/javascript/react/components/HeroSectionDesign/MyPropertiesListing.jsx +104 -0
- data/app/javascript/react/components/HeroSectionDesign/PropertiesPage.jsx +122 -0
- data/app/javascript/react/components/HotelListing/Listing.jsx +48 -0
- data/app/javascript/react/components/Layout/Layout.js +18 -0
- data/app/javascript/react/components/Listing-stay-Detail/AmenitiesFeatures.jsx +58 -0
- data/app/javascript/react/components/Listing-stay-Detail/AmenitiesModal.jsx +250 -0
- data/app/javascript/react/components/Listing-stay-Detail/ApartmentCard.jsx +120 -0
- data/app/javascript/react/components/Listing-stay-Detail/BookingModal.jsx +398 -0
- data/app/javascript/react/components/Listing-stay-Detail/CheckoutForm.jsx +296 -0
- data/app/javascript/react/components/Listing-stay-Detail/ListingStayDetailPage.jsx +512 -0
- data/app/javascript/react/components/Listing-stay-Detail/PropertyDescription.jsx +76 -0
- data/app/javascript/react/components/Listing-stay-Detail/PropertyDetailsCard.jsx +62 -0
- data/app/javascript/react/components/Listing-stay-Detail/Reviews.jsx +132 -0
- data/app/javascript/react/components/Listing-stay-Detail/RoomDescriptionModal.jsx +105 -0
- data/app/javascript/react/components/Listing-stay-Detail/Rules.jsx +23 -0
- data/app/javascript/react/components/ListingImageGallery/ListingImageGallery.jsx +30 -0
- data/app/javascript/react/components/LoginPage/LoginPage.jsx +115 -0
- data/app/javascript/react/components/MobileNav/MobileMenu.jsx +47 -0
- data/app/javascript/react/components/Navbar/Navbar.jsx +25 -0
- data/app/javascript/react/components/Page404/Page404.jsx +30 -0
- data/app/javascript/react/components/PropertyListing/MyProperties.jsx +146 -0
- data/app/javascript/react/components/PropertyListing/StayBooking/BookingDetails.jsx +178 -0
- data/app/javascript/react/components/PropertyListing/StayBooking/MyBooking.jsx +83 -0
- data/app/javascript/react/components/ResetPassword/ResetPassword.jsx +117 -0
- data/app/javascript/react/components/SignupPage/SignupPage.jsx +185 -0
- data/app/javascript/react/components/SmallNavbar/SmallNav.jsx +51 -0
- data/app/javascript/react/components/SocialAuth/SocialAuth.jsx +21 -0
- data/app/javascript/react/components/StayCard/StayCard.jsx +69 -0
- data/app/javascript/react/components/StayCard/StayCard2.jsx +45 -0
- data/app/javascript/react/components/StayCard/StayCard3.jsx +45 -0
- data/app/javascript/react/components/TestimonialSection/Testimonial.jsx +113 -0
- data/app/javascript/react/components/Unauthorized/Unauthorized.jsx +12 -0
- data/app/javascript/react/data/jsons/__countryListing.json +201 -0
- data/app/javascript/react/packs/App.js +26 -0
- data/app/javascript/react/packs/index.jsx +38 -0
- data/app/javascript/react/packs/routes/ParentRoute.jsx +14 -0
- data/app/javascript/react/packs/routes/Route.jsx +163 -0
- data/app/javascript/react/pages/AccommodationList.jsx +21 -0
- data/app/javascript/react/pages/Home.jsx +32 -0
- data/app/javascript/react/redux/slices/AuthSlice/AuthSlice.jsx +100 -0
- data/app/javascript/react/redux/slices/PropertySlice/PropertySlice.jsx +722 -0
- data/app/javascript/react/redux/slices/PropertySlice/Searchslice.jsx +36 -0
- data/app/javascript/react/redux/slices/UserSlice/UserSlice.jsx +215 -0
- data/app/javascript/react/redux/store.js +35 -0
- data/app/javascript/react/shared/Avatar/Avatar.jsx +32 -0
- data/app/javascript/react/shared/Badge/Badge.jsx +33 -0
- data/app/javascript/react/shared/Button/Button.jsx +67 -0
- data/app/javascript/react/shared/Button/ButtonPrimary.jsx +11 -0
- data/app/javascript/react/shared/Button/ButtonSelect.jsx +9 -0
- data/app/javascript/react/shared/Checkbox/Checkbox.jsx +38 -0
- data/app/javascript/react/shared/CurrencySymbol.jsx +6 -0
- data/app/javascript/react/shared/DateField/CustomDatePicker.jsx +69 -0
- data/app/javascript/react/shared/FooterSection/Footer.jsx +75 -0
- data/app/javascript/react/shared/FormField/FormField.jsx +75 -0
- data/app/javascript/react/shared/FormItem/FormItem.jsx +20 -0
- data/app/javascript/react/shared/Input/Input.jsx +27 -0
- data/app/javascript/react/shared/Label/Label.jsx +12 -0
- data/app/javascript/react/shared/Modal.jsx +20 -0
- data/app/javascript/react/shared/NcImage/NcImage.jsx +101 -0
- data/app/javascript/react/shared/NcImage/PlaceIcon.jsx +31 -0
- data/app/javascript/react/shared/NcImage/placecImageIcon.svg +6 -0
- data/app/javascript/react/shared/Select/Select.jsx +20 -0
- data/app/javascript/react/styles/404error.scss +58 -0
- data/app/javascript/react/styles/ApartmentCard.scss +126 -0
- data/app/javascript/react/styles/BookingDetails.scss +457 -0
- data/app/javascript/react/styles/Modal.scss +36 -0
- data/app/javascript/react/styles/PropertiesPage.scss +219 -0
- data/app/javascript/react/styles/RenderSection.scss +480 -0
- data/app/javascript/react/styles/about.scss +97 -0
- data/app/javascript/react/styles/accountinfo.scss +67 -0
- data/app/javascript/react/styles/accountpage.scss +36 -0
- data/app/javascript/react/styles/amenitiesfeatures.scss +223 -0
- data/app/javascript/react/styles/application.scss +87 -0
- data/app/javascript/react/styles/avatar.scss +39 -0
- data/app/javascript/react/styles/avatardropdown.scss +57 -0
- data/app/javascript/react/styles/badge.scss +90 -0
- data/app/javascript/react/styles/blog.scss +100 -0
- data/app/javascript/react/styles/bookingform.scss +124 -0
- data/app/javascript/react/styles/button.scss +44 -0
- data/app/javascript/react/styles/buttonprimary.scss +32 -0
- data/app/javascript/react/styles/checkbox.scss +37 -0
- data/app/javascript/react/styles/commonlayout.scss +83 -0
- data/app/javascript/react/styles/commonpage.scss +51 -0
- data/app/javascript/react/styles/contact.scss +173 -0
- data/app/javascript/react/styles/customdatepicker.scss +120 -0
- data/app/javascript/react/styles/description.scss +21 -0
- data/app/javascript/react/styles/details.scss +88 -0
- data/app/javascript/react/styles/facilities.scss +131 -0
- data/app/javascript/react/styles/fixednavbar.scss +137 -0
- data/app/javascript/react/styles/fonts.scss +22 -0
- data/app/javascript/react/styles/footer.scss +300 -0
- data/app/javascript/react/styles/forgetpassword.scss +68 -0
- data/app/javascript/react/styles/formfield.scss +39 -0
- data/app/javascript/react/styles/formitem.scss +20 -0
- data/app/javascript/react/styles/gallery.scss +142 -0
- data/app/javascript/react/styles/gallerymodallight.scss +137 -0
- data/app/javascript/react/styles/galleryslider.scss +114 -0
- data/app/javascript/react/styles/header.scss +49 -0
- data/app/javascript/react/styles/herosection.scss +61 -0
- data/app/javascript/react/styles/images.scss +112 -0
- data/app/javascript/react/styles/input.scss +58 -0
- data/app/javascript/react/styles/label.scss +11 -0
- data/app/javascript/react/styles/listing.scss +94 -0
- data/app/javascript/react/styles/listingimagegallery.scss +57 -0
- data/app/javascript/react/styles/listingstaydetailpage.scss +887 -0
- data/app/javascript/react/styles/location.scss +66 -0
- data/app/javascript/react/styles/loginpage.scss +150 -0
- data/app/javascript/react/styles/mobilemenu.scss +53 -0
- data/app/javascript/react/styles/mybooking.scss +104 -0
- data/app/javascript/react/styles/myproperty.scss +51 -0
- data/app/javascript/react/styles/ncimage.scss +24 -0
- data/app/javascript/react/styles/normallisting.scss +95 -0
- data/app/javascript/react/styles/property-description.scss +75 -0
- data/app/javascript/react/styles/propertycard.scss +48 -0
- data/app/javascript/react/styles/propertydetailscard.scss +302 -0
- data/app/javascript/react/styles/resetpassword.scss +79 -0
- data/app/javascript/react/styles/reviews.scss +185 -0
- data/app/javascript/react/styles/room.scss +275 -0
- data/app/javascript/react/styles/rooms.scss +0 -0
- data/app/javascript/react/styles/select.scss +44 -0
- data/app/javascript/react/styles/signuppage.scss +132 -0
- data/app/javascript/react/styles/smallnav.scss +94 -0
- data/app/javascript/react/styles/socialauth.scss +62 -0
- data/app/javascript/react/styles/speciallisting.scss +94 -0
- data/app/javascript/react/styles/staycard.scss +77 -0
- data/app/javascript/react/styles/staycard2.scss +115 -0
- data/app/javascript/react/styles/testimonial.scss +216 -0
- data/app/javascript/react/styles/unauthorized.scss +22 -0
- data/app/javascript/react/styles/variables.scss +3 -0
- data/app/javascript/react/styles/wrapper.scss +4 -0
- data/app/javascript/react/utils/formSchema.js +120 -0
- data/app/javascript/react/utils/helpers/APIHelper.jsx +55 -0
- data/app/javascript/react/utils/helpers/ErrorHandler.js +21 -0
- data/app/javascript/react/utils/helpers/InfoHandler.js +15 -0
- data/app/javascript/react/utils/helpers/SuccessHandler.js +12 -0
- data/app/javascript/react/utils/helpers/isInViewPortIntersectionObserver.jsx +39 -0
- data/app/jobs/stay_commerce/frontend/application_job.rb +6 -0
- data/app/mailers/stay_commerce/frontend/application_mailer.rb +8 -0
- data/app/models/stay_commerce/frontend/application_record.rb +7 -0
- data/app/views/layouts/stay_commerce/frontend/application.html.erb +61 -0
- data/app/views/stay_commerce/frontend/welcome/index.html.erb +2 -0
- data/config/initializers/cors.rb +6 -0
- data/config/initializers/devise.rb +359 -0
- data/config/routes.rb +11 -0
- data/lib/stay_commerce/frontend/engine.rb +14 -0
- data/lib/stay_commerce/frontend/version.rb +5 -0
- data/lib/stay_commerce/frontend.rb +8 -0
- data/lib/tasks/stay_commerce/frontend_tasks.rake +4 -0
- metadata +370 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
import React, { useState } from "react";
|
2
|
+
import "../../styles/reviews.scss";
|
3
|
+
import ButtonPrimary from "../../shared/Button/ButtonPrimary";
|
4
|
+
|
5
|
+
const Reviews = () => {
|
6
|
+
const [visibleCount, setVisibleCount] = useState(2);
|
7
|
+
|
8
|
+
const reviews = [
|
9
|
+
{
|
10
|
+
id: 1,
|
11
|
+
name: "Luciano S",
|
12
|
+
rating: 5.0,
|
13
|
+
content:
|
14
|
+
"Excellent place to stay! The apartment is beautiful and very cozy. The communication with the coliving team was very good, and they were super attentive to everything I needed. The location is excellent with many cafes and restaurants nearby. I would definitely return!",
|
15
|
+
profileImg: "https://i.pravatar.cc/100?img=1",
|
16
|
+
},
|
17
|
+
{
|
18
|
+
id: 2,
|
19
|
+
name: "Matias A",
|
20
|
+
rating: 5.0,
|
21
|
+
content:
|
22
|
+
"I stayed in a coliving and the experience was excellent. The apartment was impeccable, with a divine level of detail, well-equipped, and very comfortable. The host was attentive and responded quickly to my questions. The neighborhood is quiet but with many options to eat and drink something. Very recommended!",
|
23
|
+
profileImg: "https://i.pravatar.cc/100?img=2",
|
24
|
+
},
|
25
|
+
{
|
26
|
+
id: 3,
|
27
|
+
name: "Nico R",
|
28
|
+
rating: 5.0,
|
29
|
+
content:
|
30
|
+
"The experience, overall, was perfect! The place was clean and cozy, the staff were nice, communication was great, and the location was awesome!",
|
31
|
+
profileImg: "https://i.pravatar.cc/100?img=3",
|
32
|
+
},
|
33
|
+
{
|
34
|
+
id: 4,
|
35
|
+
name: "Mirta C",
|
36
|
+
rating: 5.0,
|
37
|
+
content:
|
38
|
+
"I loved my stay at the coliving! As a digital nomad, finding a place that combines comfort, good internet and a nice community is essential. This place exceeded my expectations.",
|
39
|
+
profileImg: "https://i.pravatar.cc/100?img=4",
|
40
|
+
},
|
41
|
+
];
|
42
|
+
|
43
|
+
const ratings = [5, 4, 3, 2, 1];
|
44
|
+
const percentages = [100, 0, 0, 0, 0];
|
45
|
+
|
46
|
+
const showMore = () => {
|
47
|
+
setVisibleCount(reviews?.length || 0);
|
48
|
+
};
|
49
|
+
|
50
|
+
const showLess = () => {
|
51
|
+
setVisibleCount(3);
|
52
|
+
};
|
53
|
+
|
54
|
+
const visibleReviews = reviews?.slice(0, visibleCount) || [];
|
55
|
+
const hasMoreReviews = visibleCount < (reviews?.length || 0);
|
56
|
+
|
57
|
+
return (
|
58
|
+
<div className="reviews-container">
|
59
|
+
<h2>Reviews</h2>
|
60
|
+
<div className="divider"></div>
|
61
|
+
|
62
|
+
<div className="reviews-summary">
|
63
|
+
<div className="rating-average">
|
64
|
+
<h1>5.0</h1>
|
65
|
+
<div className="stars">
|
66
|
+
{[...Array(5)].map((_, i) => (
|
67
|
+
<span key={i} className="star">
|
68
|
+
★
|
69
|
+
</span>
|
70
|
+
))}
|
71
|
+
</div>
|
72
|
+
<p>Excellent!</p>
|
73
|
+
<p className="review-count">Based on 19 reviews</p>
|
74
|
+
</div>
|
75
|
+
|
76
|
+
<div className="rating-bars">
|
77
|
+
{ratings?.map((rating, index) => (
|
78
|
+
<div className="rating-bar" key={rating}>
|
79
|
+
<span className="rating-number">{rating} ★</span>
|
80
|
+
<div className="progress-container">
|
81
|
+
<div
|
82
|
+
className="progress-bar"
|
83
|
+
style={{ width: `${percentages?.[index] || 0}%` }}
|
84
|
+
></div>
|
85
|
+
</div>
|
86
|
+
<span className="percentage">{percentages?.[index] || 0} %</span>
|
87
|
+
</div>
|
88
|
+
))}
|
89
|
+
</div>
|
90
|
+
</div>
|
91
|
+
|
92
|
+
<div className="reviews-list">
|
93
|
+
{visibleReviews?.map((review) => (
|
94
|
+
<div className="review-item" key={review?.id}>
|
95
|
+
<div className="user-info">
|
96
|
+
<img
|
97
|
+
src={review?.profileImg}
|
98
|
+
alt={review?.name}
|
99
|
+
className="profile-pic"
|
100
|
+
/>
|
101
|
+
<div className="user-rating">
|
102
|
+
<h3>{review?.name}</h3>
|
103
|
+
<div className="rating-display">
|
104
|
+
<span className="star">★</span>
|
105
|
+
<span className="rating-value">{review?.rating}</span>
|
106
|
+
</div>
|
107
|
+
</div>
|
108
|
+
</div>
|
109
|
+
<p className="review-content">{review?.content}</p>
|
110
|
+
<div className="review-divider"></div>
|
111
|
+
</div>
|
112
|
+
))}
|
113
|
+
|
114
|
+
{(reviews?.length || 0) > 2 && (
|
115
|
+
<div className="show-more-container">
|
116
|
+
{hasMoreReviews ? (
|
117
|
+
<ButtonPrimary className="show-more-btn" onClick={showMore}>
|
118
|
+
Show more
|
119
|
+
</ButtonPrimary>
|
120
|
+
) : (
|
121
|
+
<ButtonPrimary className="show-less-btn" onClick={showLess}>
|
122
|
+
Show less
|
123
|
+
</ButtonPrimary>
|
124
|
+
)}
|
125
|
+
</div>
|
126
|
+
)}
|
127
|
+
</div>
|
128
|
+
</div>
|
129
|
+
);
|
130
|
+
};
|
131
|
+
|
132
|
+
export default Reviews;
|
@@ -0,0 +1,105 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import { X } from "lucide-react";
|
3
|
+
|
4
|
+
const RoomDescriptionModal = ({ isOpen, onClose, room }) => {
|
5
|
+
const handleBackdropClick = (e) => {
|
6
|
+
if (e.target === e.currentTarget) {
|
7
|
+
onClose();
|
8
|
+
}
|
9
|
+
};
|
10
|
+
|
11
|
+
if (!isOpen || !room?.description) return null;
|
12
|
+
|
13
|
+
return (
|
14
|
+
<div
|
15
|
+
className="modal-overlay"
|
16
|
+
onClick={handleBackdropClick}
|
17
|
+
style={{
|
18
|
+
position: "fixed",
|
19
|
+
top: 0,
|
20
|
+
left: 0,
|
21
|
+
right: 0,
|
22
|
+
bottom: 0,
|
23
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
24
|
+
display: "flex",
|
25
|
+
alignItems: "center",
|
26
|
+
justifyContent: "center",
|
27
|
+
zIndex: 1000,
|
28
|
+
padding: "20px",
|
29
|
+
}}
|
30
|
+
>
|
31
|
+
<div
|
32
|
+
className="modal-content"
|
33
|
+
style={{
|
34
|
+
backgroundColor: "white",
|
35
|
+
borderRadius: "12px",
|
36
|
+
padding: "24px",
|
37
|
+
maxWidth: "600px",
|
38
|
+
width: "100%",
|
39
|
+
maxHeight: "80vh",
|
40
|
+
overflowY: "auto",
|
41
|
+
position: "relative",
|
42
|
+
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
|
43
|
+
}}
|
44
|
+
>
|
45
|
+
{/* Close Button */}
|
46
|
+
<button
|
47
|
+
onClick={onClose}
|
48
|
+
style={{
|
49
|
+
position: "absolute",
|
50
|
+
top: "16px",
|
51
|
+
right: "16px",
|
52
|
+
background: "none",
|
53
|
+
border: "none",
|
54
|
+
cursor: "pointer",
|
55
|
+
padding: "8px",
|
56
|
+
borderRadius: "50%",
|
57
|
+
display: "flex",
|
58
|
+
alignItems: "center",
|
59
|
+
justifyContent: "center",
|
60
|
+
transition: "background-color 0.2s",
|
61
|
+
}}
|
62
|
+
onMouseEnter={(e) => (e.target.style.backgroundColor = "#f3f4f6")}
|
63
|
+
onMouseLeave={(e) => (e.target.style.backgroundColor = "transparent")}
|
64
|
+
>
|
65
|
+
<X size={20} />
|
66
|
+
</button>
|
67
|
+
|
68
|
+
{/* Modal Header */}
|
69
|
+
<div style={{ marginBottom: "24px", paddingRight: "40px" }}>
|
70
|
+
<h2
|
71
|
+
style={{
|
72
|
+
margin: 0,
|
73
|
+
fontSize: "24px",
|
74
|
+
fontWeight: "600",
|
75
|
+
color: "#111827",
|
76
|
+
}}
|
77
|
+
>
|
78
|
+
Room Description
|
79
|
+
</h2>
|
80
|
+
<p
|
81
|
+
style={{ margin: "8px 0 0 0", color: "#6b7280", fontSize: "14px" }}
|
82
|
+
>
|
83
|
+
{room?.name}
|
84
|
+
</p>
|
85
|
+
</div>
|
86
|
+
|
87
|
+
{/* Description Body */}
|
88
|
+
<div>
|
89
|
+
<p
|
90
|
+
style={{
|
91
|
+
fontSize: "16px",
|
92
|
+
color: "#374151",
|
93
|
+
lineHeight: "1.6",
|
94
|
+
whiteSpace: "pre-line",
|
95
|
+
}}
|
96
|
+
>
|
97
|
+
{room?.description}
|
98
|
+
</p>
|
99
|
+
</div>
|
100
|
+
</div>
|
101
|
+
</div>
|
102
|
+
);
|
103
|
+
};
|
104
|
+
|
105
|
+
export default RoomDescriptionModal;
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import "../../styles/rules.scss";
|
3
|
+
|
4
|
+
const Rules = ({ propertyData }) => {
|
5
|
+
return (
|
6
|
+
<div className="policy__wrap">
|
7
|
+
<h2 className="policy__title">Property Policies & Rules</h2>
|
8
|
+
<div className="policy__divider" />
|
9
|
+
<div>
|
10
|
+
<h4 className="policy__subtitle">Special Note</h4>
|
11
|
+
<ul className="policy__rules-list">
|
12
|
+
{propertyData?.additional_rules.map((rule) => (
|
13
|
+
<li key={rule?.id} className="policy__rule">
|
14
|
+
{rule?.name}
|
15
|
+
</li>
|
16
|
+
))}
|
17
|
+
</ul>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
);
|
21
|
+
};
|
22
|
+
|
23
|
+
export default Rules;
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
import React from "react";
|
3
|
+
import { LazyLoadImage } from "react-lazy-load-image-component";
|
4
|
+
import { XMarkIcon } from "@heroicons/react/24/outline";
|
5
|
+
import "../../styles/listingimagegallery.scss";
|
6
|
+
|
7
|
+
const ListingImageGallery = ({ images, onClose }) => {
|
8
|
+
return (
|
9
|
+
<div className="image-gallery-overlay">
|
10
|
+
<div className="image-gallery-content">
|
11
|
+
<button className="close-button" onClick={onClose}>
|
12
|
+
<XMarkIcon className="close-icon" />
|
13
|
+
</button>
|
14
|
+
<div className="gallery-grid">
|
15
|
+
{images?.map((img) => (
|
16
|
+
<div key={img?.id} className="gallery-image-wrapper">
|
17
|
+
<LazyLoadImage
|
18
|
+
src={img?.url}
|
19
|
+
alt={`Image ${img?.id}`}
|
20
|
+
className="gallery-image"
|
21
|
+
/>
|
22
|
+
</div>
|
23
|
+
))}
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
);
|
28
|
+
};
|
29
|
+
|
30
|
+
export default ListingImageGallery;
|
@@ -0,0 +1,115 @@
|
|
1
|
+
import React, { useState } from "react";
|
2
|
+
import { useFormik } from "formik";
|
3
|
+
import { Link, useNavigate } from "react-router-dom";
|
4
|
+
import { useDispatch, useSelector } from "react-redux";
|
5
|
+
import "../../styles/loginpage.scss";
|
6
|
+
import { loginSchema } from "../../utils/formSchema";
|
7
|
+
import { signIn } from "../../redux/slices/AuthSlice/AuthSlice";
|
8
|
+
import { getCurrentUser } from "../../redux/slices/UserSlice/UserSlice";
|
9
|
+
import successHandler from "../../utils/helpers/SuccessHandler";
|
10
|
+
import SocialAuth from "../SocialAuth/SocialAuth";
|
11
|
+
import FormField from "../../shared/FormField/FormField";
|
12
|
+
import "../../styles/formfield.scss";
|
13
|
+
|
14
|
+
const LoginPage = () => {
|
15
|
+
const dispatch = useDispatch();
|
16
|
+
const navigate = useNavigate();
|
17
|
+
|
18
|
+
const formik = useFormik({
|
19
|
+
initialValues: {
|
20
|
+
email: "",
|
21
|
+
password: "",
|
22
|
+
},
|
23
|
+
validationSchema: loginSchema,
|
24
|
+
onSubmit: (values, { setSubmitting, resetForm }) => {
|
25
|
+
setSubmitting(true);
|
26
|
+
|
27
|
+
dispatch(signIn(values))
|
28
|
+
.unwrap()
|
29
|
+
.then((response) => {
|
30
|
+
if (response?.access_token) {
|
31
|
+
localStorage.setItem("authToken", response.access_token);
|
32
|
+
successHandler("Logged in successfully");
|
33
|
+
// dispatch(getCurrentUser());
|
34
|
+
dispatch(getCurrentUser()).then((res) => {
|
35
|
+
localStorage.setItem("user", JSON.stringify(res.payload.data)); // ⬅️ Add this
|
36
|
+
});
|
37
|
+
navigate("/");
|
38
|
+
resetForm();
|
39
|
+
} else {
|
40
|
+
console.warn("Login failed: ", response);
|
41
|
+
}
|
42
|
+
})
|
43
|
+
.catch((error) => {
|
44
|
+
console.warn("Error in login: ", error);
|
45
|
+
})
|
46
|
+
.finally(() => {
|
47
|
+
setSubmitting(false);
|
48
|
+
});
|
49
|
+
},
|
50
|
+
});
|
51
|
+
|
52
|
+
return (
|
53
|
+
<div className="login-container">
|
54
|
+
<span className="logos">👑 STAY COMMERCE</span>
|
55
|
+
<div className="main-title">
|
56
|
+
<h2>Welcome Back</h2>
|
57
|
+
<h3>Booking Platform</h3>
|
58
|
+
</div>
|
59
|
+
|
60
|
+
<div className="login-card">
|
61
|
+
<div className="log-title">
|
62
|
+
<h2>Login</h2>
|
63
|
+
</div>
|
64
|
+
<div className="social-login">
|
65
|
+
<SocialAuth />
|
66
|
+
<h4>OR</h4>
|
67
|
+
</div>
|
68
|
+
|
69
|
+
<form className="login-form" onSubmit={formik.handleSubmit}>
|
70
|
+
<FormField
|
71
|
+
label="Email"
|
72
|
+
name="email"
|
73
|
+
type="email"
|
74
|
+
placeholder="Your Email"
|
75
|
+
value={formik.values.email}
|
76
|
+
onChange={formik.handleChange}
|
77
|
+
onBlur={formik.handleBlur}
|
78
|
+
error={formik.touched.email && formik.errors.email}
|
79
|
+
/>
|
80
|
+
|
81
|
+
<FormField
|
82
|
+
label="Password"
|
83
|
+
name="password"
|
84
|
+
type="password"
|
85
|
+
placeholder="Your Password"
|
86
|
+
value={formik.values.password}
|
87
|
+
onChange={formik.handleChange}
|
88
|
+
onBlur={formik.handleBlur}
|
89
|
+
error={formik.touched.password && formik.errors.password}
|
90
|
+
/>
|
91
|
+
|
92
|
+
<button
|
93
|
+
type="submit"
|
94
|
+
className="login-button"
|
95
|
+
disabled={formik.isSubmitting}
|
96
|
+
>
|
97
|
+
{formik.isSubmitting ? "Logging in..." : "Login"}
|
98
|
+
</button>
|
99
|
+
</form>
|
100
|
+
|
101
|
+
<span className="forgot-password-link">
|
102
|
+
<Link to="/forget-password" className="forgot-password-link__text">
|
103
|
+
Forgot password?
|
104
|
+
</Link>
|
105
|
+
</span>
|
106
|
+
|
107
|
+
<p className="signup-text">
|
108
|
+
Don't have an account? <Link to="/signup">Create an account</Link>
|
109
|
+
</p>
|
110
|
+
</div>
|
111
|
+
</div>
|
112
|
+
);
|
113
|
+
};
|
114
|
+
|
115
|
+
export default LoginPage;
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import React, { useState } from "react";
|
2
|
+
import { Link, useLocation } from "react-router-dom";
|
3
|
+
import { Menu, X } from "lucide-react";
|
4
|
+
import "../../styles/mobilemenu.scss"
|
5
|
+
|
6
|
+
function MobileMenu() {
|
7
|
+
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
8
|
+
const location = useLocation();
|
9
|
+
|
10
|
+
const toggleMenu = () => setIsMenuOpen((prev) => !prev);
|
11
|
+
|
12
|
+
const navItems = [
|
13
|
+
{ name: "HOME", path: "/" },
|
14
|
+
{ name: "ABOUT US", path: "/about-us" },
|
15
|
+
{ name: "ACCOMMODATION", path: "/accommodation" },
|
16
|
+
{ name: "GALLERY", path: "/gallery" },
|
17
|
+
{ name: "BLOG", path: "/blog" },
|
18
|
+
{ name: "ELEMENT", path: "/element" },
|
19
|
+
{ name: "CONTACT", path: "/contact" },
|
20
|
+
];
|
21
|
+
|
22
|
+
return (
|
23
|
+
<div className="mobileMenu">
|
24
|
+
<div className="hamburger" onClick={toggleMenu}>
|
25
|
+
{isMenuOpen ? <X size={28} /> : <Menu size={28} />}
|
26
|
+
</div>
|
27
|
+
|
28
|
+
{/* Dropdown Menu */}
|
29
|
+
<div className={`nav ${isMenuOpen ? "open" : ""}`}>
|
30
|
+
{navItems.map((item) => (
|
31
|
+
<Link
|
32
|
+
key={item.name}
|
33
|
+
to={item.path}
|
34
|
+
className={`Link ${
|
35
|
+
location.pathname === item.path ? "active" : ""
|
36
|
+
}`}
|
37
|
+
onClick={toggleMenu}
|
38
|
+
>
|
39
|
+
{item.name}
|
40
|
+
</Link>
|
41
|
+
))}
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
);
|
45
|
+
}
|
46
|
+
|
47
|
+
export default MobileMenu;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
// import React, { useState, useEffect } from "react";
|
3
|
+
// import FixedNavbar from "../FixedNavbar/FixedNav";
|
4
|
+
// import SmallNavbar from "../SmallNavbar/SmallNav";
|
5
|
+
// import "../../styles/fixednavbar.scss";
|
6
|
+
|
7
|
+
// function Navbar() {
|
8
|
+
// const [isScrolled, setIsScrolled] = useState(false);
|
9
|
+
|
10
|
+
// useEffect(() => {
|
11
|
+
// const handleScroll = () => {
|
12
|
+
// setIsScrolled(window.scrollY > 50);
|
13
|
+
// };
|
14
|
+
|
15
|
+
// window.addEventListener("scroll", handleScroll);
|
16
|
+
// return () => window.removeEventListener("scroll", handleScroll);
|
17
|
+
// }, []);
|
18
|
+
|
19
|
+
// return isScrolled ? <FixedNavbar /> : <SmallNavbar />;
|
20
|
+
// }
|
21
|
+
|
22
|
+
|
23
|
+
// export default Navbar;
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import Img from "../../../Images/404error.jpg";
|
3
|
+
import "../../styles/404error.scss";
|
4
|
+
import { Link } from "react-router-dom";
|
5
|
+
import Navbar from "../../components/Navbar/Navbar";
|
6
|
+
import "../../styles/wrapper.scss";
|
7
|
+
|
8
|
+
const Page404 = () => (
|
9
|
+
<>
|
10
|
+
|
11
|
+
<div className="page404">
|
12
|
+
<div className="wrapper">
|
13
|
+
<div className="contain">
|
14
|
+
<img src={Img} alt="404 Error" className="page404-image" />
|
15
|
+
<h1 className="page404-title">404 - Page Not Found</h1>
|
16
|
+
<p className="page404-subtitle">
|
17
|
+
Oops! The page you're looking for doesn't exist.
|
18
|
+
</p>
|
19
|
+
<Link to="/" className="page404-button">
|
20
|
+
Return Home Page
|
21
|
+
</Link>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
</>
|
27
|
+
|
28
|
+
);
|
29
|
+
|
30
|
+
export default Page404;
|
@@ -0,0 +1,146 @@
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
2
|
+
import { useDispatch } from "react-redux";
|
3
|
+
|
4
|
+
import PropertyCard from "../Headers/PropertyCard";
|
5
|
+
import ButtonPrimary from "../../shared/Button/ButtonPrimary";
|
6
|
+
import "../../styles/myproperty.scss";
|
7
|
+
import { getallPropertieslisting } from "../../redux/slices/PropertySlice/PropertySlice";
|
8
|
+
import PropertiesPage from "../HeroSectionDesign/PropertiesPage";
|
9
|
+
import MyPropertiesListing from "../HeroSectionDesign/MyPropertiesListing";
|
10
|
+
|
11
|
+
const MyProperties = () => {
|
12
|
+
const dispatch = useDispatch();
|
13
|
+
|
14
|
+
const [allData, setAllData] = useState([]);
|
15
|
+
const [isLoading, setIsLoading] = useState(true);
|
16
|
+
const [isSearchLoading, setIsSearchLoading] = useState(false);
|
17
|
+
const [query, setQuery] = useState("");
|
18
|
+
const [page, setPage] = useState(1);
|
19
|
+
const [totalPages, setTotalPages] = useState(1);
|
20
|
+
|
21
|
+
const mergedData = (dataToBeMerged) => {
|
22
|
+
const newData = dataToBeMerged.map((apiItem) => ({
|
23
|
+
id: apiItem?.id,
|
24
|
+
title: apiItem?.title,
|
25
|
+
place_images: apiItem?.place_images,
|
26
|
+
address: `${apiItem?.city}, ${apiItem?.state}`,
|
27
|
+
availability_start: apiItem?.availability_start,
|
28
|
+
availability_end: apiItem?.availability_end,
|
29
|
+
price: apiItem?.price_per_month,
|
30
|
+
href: `/listing-stay-detail/${apiItem?.slug}`,
|
31
|
+
property_state: apiItem?.property_state || null,
|
32
|
+
active: apiItem?.active ?? false,
|
33
|
+
property_category: apiItem?.property_category?.name,
|
34
|
+
property_type: apiItem?.property_type?.name,
|
35
|
+
city: apiItem?.city,
|
36
|
+
country: apiItem?.country,
|
37
|
+
slug: apiItem?.slug,
|
38
|
+
reviewCount: apiItem?.average,
|
39
|
+
reviewTotal: apiItem?.count,
|
40
|
+
description: apiItem?.description,
|
41
|
+
}));
|
42
|
+
setAllData(newData);
|
43
|
+
};
|
44
|
+
|
45
|
+
const fetchData = async (currentPage = 1) => {
|
46
|
+
setIsLoading(true);
|
47
|
+
try {
|
48
|
+
const payload = { page: currentPage, query };
|
49
|
+
const res = await dispatch(getallPropertieslisting(payload)).unwrap();
|
50
|
+
if (res?.properties?.length > 0) {
|
51
|
+
mergedData(res.properties);
|
52
|
+
setTotalPages(res?.meta?.total_pages || 1);
|
53
|
+
} else {
|
54
|
+
setAllData([]);
|
55
|
+
setTotalPages(1); // Or 0, depending on your UI handling
|
56
|
+
}
|
57
|
+
} catch (error) {
|
58
|
+
console.error("Error fetching properties:", error);
|
59
|
+
setAllData([]);
|
60
|
+
setTotalPages(1); // Optional fallback
|
61
|
+
} finally {
|
62
|
+
setIsLoading(false);
|
63
|
+
}
|
64
|
+
};
|
65
|
+
|
66
|
+
// // 🔍 Search handler
|
67
|
+
// const handleSearch = async () => {
|
68
|
+
// if (!query.trim()) return;
|
69
|
+
// setIsSearchLoading(true);
|
70
|
+
// try {
|
71
|
+
// await fetchData(1);
|
72
|
+
// setPage(1);
|
73
|
+
// } catch (error) {
|
74
|
+
// console.error("Search error:", error);
|
75
|
+
// } finally {
|
76
|
+
// setIsSearchLoading(false);
|
77
|
+
// }
|
78
|
+
// };
|
79
|
+
const handleSearch = async () => {
|
80
|
+
if (!query.trim()) return;
|
81
|
+
setIsSearchLoading(true);
|
82
|
+
try {
|
83
|
+
const success = await fetchData(1);
|
84
|
+
if (success) {
|
85
|
+
setPage(1); // ✅ Set page only when fetch is successful
|
86
|
+
}
|
87
|
+
} catch (error) {
|
88
|
+
console.error("Search error:", error);
|
89
|
+
} finally {
|
90
|
+
setIsSearchLoading(false);
|
91
|
+
}
|
92
|
+
};
|
93
|
+
|
94
|
+
// ⌨️ Handle query input
|
95
|
+
const handleSearchChange = (event) => {
|
96
|
+
setQuery(event.target.value);
|
97
|
+
};
|
98
|
+
|
99
|
+
// 📦 Auto-fetch on mount or when query is cleared
|
100
|
+
useEffect(() => {
|
101
|
+
if (query.length === 0) {
|
102
|
+
fetchData(1);
|
103
|
+
}
|
104
|
+
}, [query]);
|
105
|
+
|
106
|
+
return (
|
107
|
+
<div className="myListing-page">
|
108
|
+
<div className="myListing-content">
|
109
|
+
<div className="myListing-header">
|
110
|
+
{/* 🔍 Search Input */}
|
111
|
+
{/* <div className="myListing-search">
|
112
|
+
<div className="search-bar">
|
113
|
+
<input
|
114
|
+
type="text"
|
115
|
+
value={query}
|
116
|
+
onChange={handleSearchChange}
|
117
|
+
placeholder="Search By Property Name..."
|
118
|
+
className="search-input"
|
119
|
+
/>
|
120
|
+
<ButtonPrimary
|
121
|
+
onClick={handleSearch}
|
122
|
+
className={`search-button ${
|
123
|
+
isSearchLoading || query.trim() === ""
|
124
|
+
? "search-button-disabled"
|
125
|
+
: "search-button-active"
|
126
|
+
}`}
|
127
|
+
disabled={isSearchLoading || query.trim() === ""}
|
128
|
+
>
|
129
|
+
{isSearchLoading ? "Searching..." : "Search"}
|
130
|
+
</ButtonPrimary>
|
131
|
+
</div>
|
132
|
+
</div> */}
|
133
|
+
<div className="myListing-property-cards">
|
134
|
+
<MyPropertiesListing
|
135
|
+
heading="My Properties"
|
136
|
+
stayListings={allData}
|
137
|
+
setAllData={setAllData}
|
138
|
+
/>
|
139
|
+
</div>
|
140
|
+
</div>
|
141
|
+
</div>
|
142
|
+
</div>
|
143
|
+
);
|
144
|
+
};
|
145
|
+
|
146
|
+
export default MyProperties;
|