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.
Files changed (242) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/builds/404error-RVKQJ4S4.digested.jpg +0 -0
  6. data/app/assets/builds/Facebook-5HJUILVR.digested.svg +3 -0
  7. data/app/assets/builds/Google-CZ3UPVSC.digested.svg +6 -0
  8. data/app/assets/builds/application.js +95 -0
  9. data/app/assets/builds/application.js.map +7 -0
  10. data/app/assets/builds/beach-KAZW5GM3.digested.jpg +0 -0
  11. data/app/assets/builds/beach2-3ARC34NS.digested.jpg +0 -0
  12. data/app/assets/builds/beach3-PSTOH5FV.digested.jpg +0 -0
  13. data/app/assets/builds/beach4-PWNRPD3S.digested.jpg +0 -0
  14. data/app/assets/builds/beach5-SBOKKRHF.digested.jpg +0 -0
  15. data/app/assets/builds/beach6-SXZ5Y5AI.digested.jpg +0 -0
  16. data/app/assets/builds/beach7-FNBMFVKK.digested.jpg +0 -0
  17. data/app/assets/builds/beach8-TD7LTRQM.digested.jpg +0 -0
  18. data/app/assets/builds/bg-image-H7UGUMV2.digested.jpg +0 -0
  19. data/app/assets/builds/bgimage-DU3PCXKN.digested.jpg +0 -0
  20. data/app/assets/builds/bundle.css +30914 -0
  21. data/app/assets/builds/bundle.css.map +7 -0
  22. data/app/assets/builds/bundle.js +74569 -0
  23. data/app/assets/builds/bundle.js.map +7 -0
  24. data/app/assets/builds/hotel1-HGBXPKJK.digested.jpg +0 -0
  25. data/app/assets/builds/logo_updated-KQWAXLYL.digested.png +0 -0
  26. data/app/assets/builds/styles.css +6422 -0
  27. data/app/assets/builds/styles.css.map +7 -0
  28. data/app/assets/config/manifest.js +2 -0
  29. data/app/assets/images/favicon.ico +0 -0
  30. data/app/assets/images/stay_commerce/frontend/beach-666122_1280 (1).jpg +0 -0
  31. data/app/assets/images/stay_commerce/frontend/beach-666122_1280.jpg +0 -0
  32. data/app/assets/stylesheets/stay_commerce/frontend/application.css +15 -0
  33. data/app/controllers/stay_commerce/frontend/application_controller.rb +8 -0
  34. data/app/controllers/stay_commerce/frontend/welcome_controller.rb +6 -0
  35. data/app/helpers/stay_commerce/frontend/application_helper.rb +6 -0
  36. data/app/javascript/Images/404error.jpg +0 -0
  37. data/app/javascript/Images/Facebook.svg +3 -0
  38. data/app/javascript/Images/Google.svg +6 -0
  39. data/app/javascript/Images/beach-2245867_1280.jpg +0 -0
  40. data/app/javascript/Images/beach.jpg +0 -0
  41. data/app/javascript/Images/beach2.jpg +0 -0
  42. data/app/javascript/Images/beach3.jpg +0 -0
  43. data/app/javascript/Images/beach4.jpg +0 -0
  44. data/app/javascript/Images/beach5.jpg +0 -0
  45. data/app/javascript/Images/beach6.jpg +0 -0
  46. data/app/javascript/Images/beach7.jpg +0 -0
  47. data/app/javascript/Images/beach8.jpg +0 -0
  48. data/app/javascript/Images/bg-image.jpg +0 -0
  49. data/app/javascript/Images/bgimage.jpg +0 -0
  50. data/app/javascript/Images/blog-1.jpg +0 -0
  51. data/app/javascript/Images/gallery.png +0 -0
  52. data/app/javascript/Images/home 5.jpg +0 -0
  53. data/app/javascript/Images/home1.jpg +0 -0
  54. data/app/javascript/Images/home2.jpg +0 -0
  55. data/app/javascript/Images/home3.jpg +0 -0
  56. data/app/javascript/Images/home6.jpg +0 -0
  57. data/app/javascript/Images/hotel1.jpg +0 -0
  58. data/app/javascript/Images/room1.jpg +0 -0
  59. data/app/javascript/Images/room2.jpg +0 -0
  60. data/app/javascript/Images/room3.jpg +0 -0
  61. data/app/javascript/Images/room4.jpg +0 -0
  62. data/app/javascript/Images/wine-4520213_1280.jpg +0 -0
  63. data/app/javascript/application.js +1 -0
  64. data/app/javascript/react/Api/apiConstants.js +47 -0
  65. data/app/javascript/react/assets/beach-2245867_1280.jpg +0 -0
  66. data/app/javascript/react/assets/logo.png +0 -0
  67. data/app/javascript/react/assets/logo_updated.png +0 -0
  68. data/app/javascript/react/components/AboutUsPage/AboutPage.jsx +41 -0
  69. data/app/javascript/react/components/AboutusFront/About.jsx +37 -0
  70. data/app/javascript/react/components/Accommodation/Accommodation.jsx +32 -0
  71. data/app/javascript/react/components/Accommodation/NormalListing.jsx +50 -0
  72. data/app/javascript/react/components/Accommodation/SpecialListing.jsx +51 -0
  73. data/app/javascript/react/components/Accountpage/AccountInfo.jsx +217 -0
  74. data/app/javascript/react/components/Accountpage/AccountPage.jsx +27 -0
  75. data/app/javascript/react/components/Accountpage/CommonPage.jsx +24 -0
  76. data/app/javascript/react/components/AddNewProperty/CommonLayout.jsx +68 -0
  77. data/app/javascript/react/components/AddNewProperty/Description.jsx +229 -0
  78. data/app/javascript/react/components/AddNewProperty/Details.jsx +234 -0
  79. data/app/javascript/react/components/AddNewProperty/Images.jsx +196 -0
  80. data/app/javascript/react/components/AddNewProperty/Location.jsx +239 -0
  81. data/app/javascript/react/components/AddNewProperty/Room.jsx +1132 -0
  82. data/app/javascript/react/components/AvatarDropdown/AvatarDropDown.jsx +142 -0
  83. data/app/javascript/react/components/BlogDesign/BlogsLatest.jsx +67 -0
  84. data/app/javascript/react/components/ContactUs/Contact.jsx +89 -0
  85. data/app/javascript/react/components/FacilitiesSection/Facilities.jsx +66 -0
  86. data/app/javascript/react/components/FixedNavbar/FixedNav.jsx +88 -0
  87. data/app/javascript/react/components/ForgetPassword/ForgetPassword.jsx +103 -0
  88. data/app/javascript/react/components/Gallery/Gallery.jsx +164 -0
  89. data/app/javascript/react/components/GalleryModalLight/GalleryModalLight.jsx +35 -0
  90. data/app/javascript/react/components/GallerySlider/GallerySlider.jsx +58 -0
  91. data/app/javascript/react/components/Headers/PropertyCard.jsx +46 -0
  92. data/app/javascript/react/components/HeroSectionDesign/BookingForm.jsx +178 -0
  93. data/app/javascript/react/components/HeroSectionDesign/HeroSection.jsx +29 -0
  94. data/app/javascript/react/components/HeroSectionDesign/MyPropertiesListing.jsx +104 -0
  95. data/app/javascript/react/components/HeroSectionDesign/PropertiesPage.jsx +122 -0
  96. data/app/javascript/react/components/HotelListing/Listing.jsx +48 -0
  97. data/app/javascript/react/components/Layout/Layout.js +18 -0
  98. data/app/javascript/react/components/Listing-stay-Detail/AmenitiesFeatures.jsx +58 -0
  99. data/app/javascript/react/components/Listing-stay-Detail/AmenitiesModal.jsx +250 -0
  100. data/app/javascript/react/components/Listing-stay-Detail/ApartmentCard.jsx +120 -0
  101. data/app/javascript/react/components/Listing-stay-Detail/BookingModal.jsx +398 -0
  102. data/app/javascript/react/components/Listing-stay-Detail/CheckoutForm.jsx +296 -0
  103. data/app/javascript/react/components/Listing-stay-Detail/ListingStayDetailPage.jsx +512 -0
  104. data/app/javascript/react/components/Listing-stay-Detail/PropertyDescription.jsx +76 -0
  105. data/app/javascript/react/components/Listing-stay-Detail/PropertyDetailsCard.jsx +62 -0
  106. data/app/javascript/react/components/Listing-stay-Detail/Reviews.jsx +132 -0
  107. data/app/javascript/react/components/Listing-stay-Detail/RoomDescriptionModal.jsx +105 -0
  108. data/app/javascript/react/components/Listing-stay-Detail/Rules.jsx +23 -0
  109. data/app/javascript/react/components/ListingImageGallery/ListingImageGallery.jsx +30 -0
  110. data/app/javascript/react/components/LoginPage/LoginPage.jsx +115 -0
  111. data/app/javascript/react/components/MobileNav/MobileMenu.jsx +47 -0
  112. data/app/javascript/react/components/Navbar/Navbar.jsx +25 -0
  113. data/app/javascript/react/components/Page404/Page404.jsx +30 -0
  114. data/app/javascript/react/components/PropertyListing/MyProperties.jsx +146 -0
  115. data/app/javascript/react/components/PropertyListing/StayBooking/BookingDetails.jsx +178 -0
  116. data/app/javascript/react/components/PropertyListing/StayBooking/MyBooking.jsx +83 -0
  117. data/app/javascript/react/components/ResetPassword/ResetPassword.jsx +117 -0
  118. data/app/javascript/react/components/SignupPage/SignupPage.jsx +185 -0
  119. data/app/javascript/react/components/SmallNavbar/SmallNav.jsx +51 -0
  120. data/app/javascript/react/components/SocialAuth/SocialAuth.jsx +21 -0
  121. data/app/javascript/react/components/StayCard/StayCard.jsx +69 -0
  122. data/app/javascript/react/components/StayCard/StayCard2.jsx +45 -0
  123. data/app/javascript/react/components/StayCard/StayCard3.jsx +45 -0
  124. data/app/javascript/react/components/TestimonialSection/Testimonial.jsx +113 -0
  125. data/app/javascript/react/components/Unauthorized/Unauthorized.jsx +12 -0
  126. data/app/javascript/react/data/jsons/__countryListing.json +201 -0
  127. data/app/javascript/react/packs/App.js +26 -0
  128. data/app/javascript/react/packs/index.jsx +38 -0
  129. data/app/javascript/react/packs/routes/ParentRoute.jsx +14 -0
  130. data/app/javascript/react/packs/routes/Route.jsx +163 -0
  131. data/app/javascript/react/pages/AccommodationList.jsx +21 -0
  132. data/app/javascript/react/pages/Home.jsx +32 -0
  133. data/app/javascript/react/redux/slices/AuthSlice/AuthSlice.jsx +100 -0
  134. data/app/javascript/react/redux/slices/PropertySlice/PropertySlice.jsx +722 -0
  135. data/app/javascript/react/redux/slices/PropertySlice/Searchslice.jsx +36 -0
  136. data/app/javascript/react/redux/slices/UserSlice/UserSlice.jsx +215 -0
  137. data/app/javascript/react/redux/store.js +35 -0
  138. data/app/javascript/react/shared/Avatar/Avatar.jsx +32 -0
  139. data/app/javascript/react/shared/Badge/Badge.jsx +33 -0
  140. data/app/javascript/react/shared/Button/Button.jsx +67 -0
  141. data/app/javascript/react/shared/Button/ButtonPrimary.jsx +11 -0
  142. data/app/javascript/react/shared/Button/ButtonSelect.jsx +9 -0
  143. data/app/javascript/react/shared/Checkbox/Checkbox.jsx +38 -0
  144. data/app/javascript/react/shared/CurrencySymbol.jsx +6 -0
  145. data/app/javascript/react/shared/DateField/CustomDatePicker.jsx +69 -0
  146. data/app/javascript/react/shared/FooterSection/Footer.jsx +75 -0
  147. data/app/javascript/react/shared/FormField/FormField.jsx +75 -0
  148. data/app/javascript/react/shared/FormItem/FormItem.jsx +20 -0
  149. data/app/javascript/react/shared/Input/Input.jsx +27 -0
  150. data/app/javascript/react/shared/Label/Label.jsx +12 -0
  151. data/app/javascript/react/shared/Modal.jsx +20 -0
  152. data/app/javascript/react/shared/NcImage/NcImage.jsx +101 -0
  153. data/app/javascript/react/shared/NcImage/PlaceIcon.jsx +31 -0
  154. data/app/javascript/react/shared/NcImage/placecImageIcon.svg +6 -0
  155. data/app/javascript/react/shared/Select/Select.jsx +20 -0
  156. data/app/javascript/react/styles/404error.scss +58 -0
  157. data/app/javascript/react/styles/ApartmentCard.scss +126 -0
  158. data/app/javascript/react/styles/BookingDetails.scss +457 -0
  159. data/app/javascript/react/styles/Modal.scss +36 -0
  160. data/app/javascript/react/styles/PropertiesPage.scss +219 -0
  161. data/app/javascript/react/styles/RenderSection.scss +480 -0
  162. data/app/javascript/react/styles/about.scss +97 -0
  163. data/app/javascript/react/styles/accountinfo.scss +67 -0
  164. data/app/javascript/react/styles/accountpage.scss +36 -0
  165. data/app/javascript/react/styles/amenitiesfeatures.scss +223 -0
  166. data/app/javascript/react/styles/application.scss +87 -0
  167. data/app/javascript/react/styles/avatar.scss +39 -0
  168. data/app/javascript/react/styles/avatardropdown.scss +57 -0
  169. data/app/javascript/react/styles/badge.scss +90 -0
  170. data/app/javascript/react/styles/blog.scss +100 -0
  171. data/app/javascript/react/styles/bookingform.scss +124 -0
  172. data/app/javascript/react/styles/button.scss +44 -0
  173. data/app/javascript/react/styles/buttonprimary.scss +32 -0
  174. data/app/javascript/react/styles/checkbox.scss +37 -0
  175. data/app/javascript/react/styles/commonlayout.scss +83 -0
  176. data/app/javascript/react/styles/commonpage.scss +51 -0
  177. data/app/javascript/react/styles/contact.scss +173 -0
  178. data/app/javascript/react/styles/customdatepicker.scss +120 -0
  179. data/app/javascript/react/styles/description.scss +21 -0
  180. data/app/javascript/react/styles/details.scss +88 -0
  181. data/app/javascript/react/styles/facilities.scss +131 -0
  182. data/app/javascript/react/styles/fixednavbar.scss +137 -0
  183. data/app/javascript/react/styles/fonts.scss +22 -0
  184. data/app/javascript/react/styles/footer.scss +300 -0
  185. data/app/javascript/react/styles/forgetpassword.scss +68 -0
  186. data/app/javascript/react/styles/formfield.scss +39 -0
  187. data/app/javascript/react/styles/formitem.scss +20 -0
  188. data/app/javascript/react/styles/gallery.scss +142 -0
  189. data/app/javascript/react/styles/gallerymodallight.scss +137 -0
  190. data/app/javascript/react/styles/galleryslider.scss +114 -0
  191. data/app/javascript/react/styles/header.scss +49 -0
  192. data/app/javascript/react/styles/herosection.scss +61 -0
  193. data/app/javascript/react/styles/images.scss +112 -0
  194. data/app/javascript/react/styles/input.scss +58 -0
  195. data/app/javascript/react/styles/label.scss +11 -0
  196. data/app/javascript/react/styles/listing.scss +94 -0
  197. data/app/javascript/react/styles/listingimagegallery.scss +57 -0
  198. data/app/javascript/react/styles/listingstaydetailpage.scss +887 -0
  199. data/app/javascript/react/styles/location.scss +66 -0
  200. data/app/javascript/react/styles/loginpage.scss +150 -0
  201. data/app/javascript/react/styles/mobilemenu.scss +53 -0
  202. data/app/javascript/react/styles/mybooking.scss +104 -0
  203. data/app/javascript/react/styles/myproperty.scss +51 -0
  204. data/app/javascript/react/styles/ncimage.scss +24 -0
  205. data/app/javascript/react/styles/normallisting.scss +95 -0
  206. data/app/javascript/react/styles/property-description.scss +75 -0
  207. data/app/javascript/react/styles/propertycard.scss +48 -0
  208. data/app/javascript/react/styles/propertydetailscard.scss +302 -0
  209. data/app/javascript/react/styles/resetpassword.scss +79 -0
  210. data/app/javascript/react/styles/reviews.scss +185 -0
  211. data/app/javascript/react/styles/room.scss +275 -0
  212. data/app/javascript/react/styles/rooms.scss +0 -0
  213. data/app/javascript/react/styles/select.scss +44 -0
  214. data/app/javascript/react/styles/signuppage.scss +132 -0
  215. data/app/javascript/react/styles/smallnav.scss +94 -0
  216. data/app/javascript/react/styles/socialauth.scss +62 -0
  217. data/app/javascript/react/styles/speciallisting.scss +94 -0
  218. data/app/javascript/react/styles/staycard.scss +77 -0
  219. data/app/javascript/react/styles/staycard2.scss +115 -0
  220. data/app/javascript/react/styles/testimonial.scss +216 -0
  221. data/app/javascript/react/styles/unauthorized.scss +22 -0
  222. data/app/javascript/react/styles/variables.scss +3 -0
  223. data/app/javascript/react/styles/wrapper.scss +4 -0
  224. data/app/javascript/react/utils/formSchema.js +120 -0
  225. data/app/javascript/react/utils/helpers/APIHelper.jsx +55 -0
  226. data/app/javascript/react/utils/helpers/ErrorHandler.js +21 -0
  227. data/app/javascript/react/utils/helpers/InfoHandler.js +15 -0
  228. data/app/javascript/react/utils/helpers/SuccessHandler.js +12 -0
  229. data/app/javascript/react/utils/helpers/isInViewPortIntersectionObserver.jsx +39 -0
  230. data/app/jobs/stay_commerce/frontend/application_job.rb +6 -0
  231. data/app/mailers/stay_commerce/frontend/application_mailer.rb +8 -0
  232. data/app/models/stay_commerce/frontend/application_record.rb +7 -0
  233. data/app/views/layouts/stay_commerce/frontend/application.html.erb +61 -0
  234. data/app/views/stay_commerce/frontend/welcome/index.html.erb +2 -0
  235. data/config/initializers/cors.rb +6 -0
  236. data/config/initializers/devise.rb +359 -0
  237. data/config/routes.rb +11 -0
  238. data/lib/stay_commerce/frontend/engine.rb +14 -0
  239. data/lib/stay_commerce/frontend/version.rb +5 -0
  240. data/lib/stay_commerce/frontend.rb +8 -0
  241. data/lib/tasks/stay_commerce/frontend_tasks.rake +4 -0
  242. metadata +370 -0
@@ -0,0 +1,36 @@
1
+ import { createSlice } from "@reduxjs/toolkit";
2
+ import { searchProperties } from "./PropertySlice";
3
+
4
+ const initialState = {
5
+ searchResults: [],
6
+ startDate: null,
7
+ endDate: null,
8
+ totalGuests: 1,
9
+ };
10
+
11
+ const searchSlice = createSlice({
12
+ name: "search",
13
+ initialState,
14
+ reducers: {
15
+ clearSearchResults: (state) => {
16
+ state.searchResults = [];
17
+ state.startDate = null;
18
+ state.endDate = null;
19
+ state.totalGuests = 1;
20
+ },
21
+ setSearchMeta: (state, action) => {
22
+ const { startDate, endDate, totalGuests } = action.payload;
23
+ state.startDate = startDate;
24
+ state.endDate = endDate;
25
+ state.totalGuests = totalGuests;
26
+ },
27
+ },
28
+ extraReducers: (builder) => {
29
+ builder.addCase(searchProperties.fulfilled, (state, action) => {
30
+ state.searchResults = action.payload.data || [];
31
+ });
32
+ },
33
+ });
34
+
35
+ export const { clearSearchResults, setSearchMeta } = searchSlice.actions;
36
+ export default searchSlice.reducer;
@@ -0,0 +1,215 @@
1
+ import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
2
+ import axios from "axios";
3
+ import { ENDPOINTS } from "../../../Api/apiConstants";
4
+ import ErrorHandler from "../../../utils/helpers/ErrorHandler";
5
+ export const getCurrentUser = createAsyncThunk(
6
+ "user/getCurrentUser",
7
+ async (_, { rejectWithValue }) => {
8
+ try {
9
+ const token = localStorage.getItem("authToken");
10
+ if (!token) throw new Error("No token found");
11
+
12
+ const response = await axios.get(ENDPOINTS?.USER_INFO, {
13
+ headers: { Authorization: `Bearer ${token}` },
14
+ });
15
+ return response?.data;
16
+ } catch (error) {
17
+ ErrorHandler?.(error);
18
+ return rejectWithValue(error?.response?.data || "Failed to fetch user");
19
+ }
20
+ }
21
+ );
22
+
23
+ // Update User Profile
24
+ export const updateUser = createAsyncThunk(
25
+ "user/updateUser",
26
+ async (updatedData, { rejectWithValue }) => {
27
+ try {
28
+ const token = localStorage.getItem("authToken");
29
+ if (!token) throw new Error("No token found");
30
+
31
+ const response = await axios.patch(
32
+ ENDPOINTS?.USER_UPDATE?.(updatedData?.profile?.id),
33
+ updatedData?.profile,
34
+ {
35
+ headers: { Authorization: `Bearer ${token}` },
36
+ }
37
+ );
38
+
39
+ return response?.data;
40
+ } catch (error) {
41
+ ErrorHandler?.(error);
42
+ return rejectWithValue(
43
+ error?.response?.data || "Failed to update profile"
44
+ );
45
+ }
46
+ }
47
+ );
48
+
49
+ export const updateProfileImage = createAsyncThunk(
50
+ "user/updateProfileImage",
51
+ async ({ userId, file }, { rejectWithValue }) => {
52
+ try {
53
+ const token = localStorage.getItem("authToken");
54
+ if (!token) throw new Error("No token found");
55
+
56
+ const formData = new FormData();
57
+ formData.append("profile[profile_image]", file);
58
+
59
+ const response = await axios.patch(
60
+ ENDPOINTS?.USER_UPDATE?.(userId),
61
+ formData,
62
+ {
63
+ headers: {
64
+ Authorization: `Bearer ${token}`,
65
+ "Content-Type": "multipart/form-data",
66
+ },
67
+ }
68
+ );
69
+
70
+ return response?.data;
71
+ } catch (error) {
72
+ ErrorHandler?.(error);
73
+ return rejectWithValue(
74
+ error?.response?.data || "Failed to update profile image"
75
+ );
76
+ }
77
+ }
78
+ );
79
+
80
+ export const forgetPassword = createAsyncThunk(
81
+ "user/forgetPassword",
82
+ async (payload, { rejectWithValue }) => {
83
+ try {
84
+ const response = await axios.post(ENDPOINTS?.EDIT_PASSWORD, payload, {
85
+ headers: {
86
+ Accept: "application/json",
87
+ "Content-Type": "application/json",
88
+ },
89
+ });
90
+ return response?.data;
91
+ } catch (error) {
92
+ ErrorHandler?.(error);
93
+ return rejectWithValue(
94
+ error?.response?.data || "Failed to update password"
95
+ );
96
+ }
97
+ }
98
+ );
99
+
100
+ export const createNewPassword = createAsyncThunk(
101
+ "user/createNewPassword",
102
+ async ({ token, payload }, { rejectWithValue }) => {
103
+ try {
104
+ const response = await axios.patch(
105
+ `${ENDPOINTS?.EDIT_PASSWORD}?reset_password_token=${token}`,
106
+ payload,
107
+ {
108
+ headers: {
109
+ "Content-Type": "application/json",
110
+ Accept: "application/json",
111
+ },
112
+ }
113
+ );
114
+ return response?.data;
115
+ } catch (error) {
116
+ ErrorHandler?.(error);
117
+ return rejectWithValue(
118
+ error?.response?.data || "Failed to reset password"
119
+ );
120
+ }
121
+ }
122
+ );
123
+
124
+
125
+ const handlePending = (state) => {
126
+ state.loading = true;
127
+ state.error = null;
128
+ };
129
+
130
+ const handleRejected = (state, action) => {
131
+ state.loading = false;
132
+ state.error = action.payload;
133
+ };
134
+
135
+ const handleUpdatePending = (state) => {
136
+ state.updateLoading = true;
137
+ state.updateError = null;
138
+ };
139
+
140
+ const handleUpdateRejected = (state, action) => {
141
+ state.updateLoading = false;
142
+ state.updateError = action.payload;
143
+ };
144
+
145
+ const userSlice = createSlice({
146
+ name: "user",
147
+ initialState: {
148
+ data: JSON.parse(localStorage.getItem("user")) || null,
149
+ loading: false,
150
+ error: null,
151
+ updateLoading: false,
152
+ updateError: null,
153
+ },
154
+ reducers: {
155
+ logout: (state) => {
156
+ state.data = null;
157
+ localStorage.removeItem("authToken");
158
+ },
159
+ },
160
+ extraReducers: (builder) => {
161
+ builder
162
+ // Get current user
163
+ .addCase(getCurrentUser.pending, handlePending)
164
+ .addCase(getCurrentUser.fulfilled, (state, action) => {
165
+ state.loading = false;
166
+ const userData = action.payload.data;
167
+ // Store is_host and is_user directly
168
+ state.data = {
169
+ ...userData,
170
+ is_host: userData.is_host,
171
+ is_user: userData.is_user,
172
+ };
173
+ localStorage.setItem("user", JSON.stringify(action.payload.data));
174
+ })
175
+ .addCase(getCurrentUser.rejected, handleRejected)
176
+
177
+ // Update user
178
+ .addCase(updateUser.pending, handleUpdatePending)
179
+ .addCase(updateUser.fulfilled, (state, action) => {
180
+ state.updateLoading = false;
181
+ state.data = {
182
+ ...state.data,
183
+ ...action.payload.profile,
184
+ };
185
+ localStorage.setItem("user", JSON.stringify(state.data));
186
+ })
187
+ .addCase(updateUser.rejected, handleUpdateRejected)
188
+
189
+ // Update profile image
190
+ .addCase(updateProfileImage.pending, handleUpdatePending)
191
+ .addCase(updateProfileImage.fulfilled, (state, action) => {
192
+ state.updateLoading = false;
193
+ if (state.data) {
194
+ state.data.image = action.payload.profile.image;
195
+ localStorage.setItem("user", JSON.stringify(state.data));
196
+ }
197
+ })
198
+ .addCase(updateProfileImage.rejected, handleUpdateRejected)
199
+
200
+ .addCase(forgetPassword.pending, handlePending)
201
+ .addCase(forgetPassword.fulfilled, (state) => {
202
+ state.loading = false;
203
+ })
204
+ .addCase(forgetPassword.rejected, handleRejected)
205
+
206
+ .addCase(createNewPassword.pending, handlePending)
207
+ .addCase(createNewPassword.fulfilled, (state) => {
208
+ state.loading = false;
209
+ })
210
+ .addCase(createNewPassword.rejected, handleRejected);
211
+ },
212
+ });
213
+
214
+ export const { logout } = userSlice.actions;
215
+ export default userSlice.reducer;
@@ -0,0 +1,35 @@
1
+
2
+
3
+ import { configureStore, combineReducers } from "@reduxjs/toolkit";
4
+ import authReducer from "./slices/AuthSlice/AuthSlice";
5
+ import userReducer from "./slices/UserSlice/UserSlice";
6
+ import propertyReducer from "./slices/PropertySlice/PropertySlice";
7
+ import searchReducer from "./slices/PropertySlice/Searchslice";
8
+
9
+ import storage from "redux-persist/lib/storage";
10
+ import { persistReducer, persistStore } from "redux-persist";
11
+
12
+ const persistConfig = {
13
+ key: "root",
14
+ storage,
15
+ whitelist: ["auth", "user" ,"property", "search"],
16
+ };
17
+
18
+ const rootReducer = combineReducers({
19
+ auth: authReducer,
20
+ user: userReducer,
21
+ property: propertyReducer,
22
+ search: searchReducer,
23
+ });
24
+
25
+ const persistedReducer = persistReducer(persistConfig, rootReducer);
26
+
27
+ const store = configureStore({
28
+ reducer: persistedReducer,
29
+ middleware: (getDefaultMiddleware) =>
30
+ getDefaultMiddleware({ serializableCheck: false }),
31
+ });
32
+
33
+ export const persistor = persistStore(store);
34
+ export default store;
35
+
@@ -0,0 +1,32 @@
1
+ import React from "react";
2
+ import { useSelector } from "react-redux";
3
+ import "../../styles/avatar.scss";
4
+
5
+ const Avatar = ({ onClick, sizeClass = "" }) => {
6
+ const userData = useSelector((state) => state.user.data);
7
+
8
+ if (!userData) return null;
9
+
10
+ const profileImage = userData.image;
11
+ const firstLetter = userData.first_name?.charAt(0).toUpperCase() || "?";
12
+
13
+ return (
14
+ <div className={`avatar-container ${sizeClass}`} onClick={onClick}>
15
+ {profileImage ? (
16
+ <img
17
+ src={profileImage}
18
+ alt="Profile"
19
+ className="avatar-image"
20
+ onError={(e) => {
21
+ e.target.onerror = null;
22
+ // e.target.src = "/default-avatar.png"; // optional fallback image
23
+ }}
24
+ />
25
+ ) : (
26
+ <div className="avatar-circle">{firstLetter}</div>
27
+ )}
28
+ </div>
29
+ );
30
+ };
31
+
32
+ export default Avatar;
@@ -0,0 +1,33 @@
1
+ import React from "react";
2
+ import { Link } from "react-router-dom";
3
+ import "../../styles/badge.scss"
4
+
5
+ const Badge = ({ className = "", name, color = "blue", href }) => {
6
+ const getColorClass = (hasHover = true) => {
7
+ switch (color) {
8
+ case "pink":
9
+ case "red":
10
+ case "gray":
11
+ case "green":
12
+ case "purple":
13
+ case "indigo":
14
+ case "yellow":
15
+ case "blue":
16
+ return `${color}-badge${hasHover ? " hover" : ""}`;
17
+ default:
18
+ return `pink-badge${hasHover ? " hover" : ""}`;
19
+ }
20
+ };
21
+
22
+ const baseClass = `badge ${className} ${getColorClass(!!href)}`;
23
+
24
+ return href ? (
25
+ <Link to={href} className={baseClass}>
26
+ {name}
27
+ </Link>
28
+ ) : (
29
+ <span className={baseClass}>{name}</span>
30
+ );
31
+ };
32
+
33
+ export default Badge;
@@ -0,0 +1,67 @@
1
+ import React from "react";
2
+ import { Link } from "react-router-dom";
3
+ import "../../styles/button.scss";
4
+
5
+ const Button = ({
6
+ className = "button-default",
7
+ disabled = false,
8
+ href,
9
+ children,
10
+ targetBlank,
11
+ type,
12
+ loading,
13
+ onClick = () => {},
14
+ }) => {
15
+ const renderLoading = () => {
16
+ return (
17
+ <svg
18
+ className="button-loading"
19
+ xmlns="http://www.w3.org/2000/svg"
20
+ fill="none"
21
+ viewBox="0 0 24 24"
22
+ >
23
+ <circle
24
+ className="opacity-25"
25
+ cx="12"
26
+ cy="12"
27
+ r="10"
28
+ stroke="currentColor"
29
+ strokeWidth="3"
30
+ ></circle>
31
+ <path
32
+ className="opacity-75"
33
+ fill="currentColor"
34
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
35
+ ></path>
36
+ </svg>
37
+ );
38
+ };
39
+
40
+ if (href) {
41
+ return (
42
+ <Link
43
+ to={href}
44
+ target={targetBlank ? "_blank" : undefined}
45
+ className={`button ${className}`}
46
+ onClick={onClick}
47
+ rel="noopener noreferrer"
48
+ >
49
+ {children || "This is Link"}
50
+ </Link>
51
+ );
52
+ }
53
+
54
+ return (
55
+ <button
56
+ disabled={disabled || loading}
57
+ className={`button ${className}`}
58
+ onClick={onClick}
59
+ type={type}
60
+ >
61
+ {loading && renderLoading()}
62
+ {children || "This is Button"}
63
+ </button>
64
+ );
65
+ };
66
+
67
+ export default Button;
@@ -0,0 +1,11 @@
1
+ import Button from "./Button";
2
+ import React from "react";
3
+ import "../../styles/buttonprimary.scss"; // Import SCSS for styling
4
+
5
+ const ButtonPrimary = ({ className = "", ...args }) => {
6
+ return (
7
+ <Button className={`btn-primary ${className}`} {...args} />
8
+ );
9
+ };
10
+
11
+ export default ButtonPrimary;
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import Button from "./Button";
3
+ import "../../styles/button.scss";
4
+
5
+ const ButtonSelect = ({ className = "button-third", ...args }) => {
6
+ return <Button className={`button-third ${className}`} {...args} />;
7
+ };
8
+
9
+ export default ButtonSelect;
@@ -0,0 +1,38 @@
1
+ import React from "react";
2
+ import "../../styles/checkbox.scss";
3
+
4
+ const CheckboxV2 = ({
5
+ id,
6
+ label = "",
7
+ subLabel = "",
8
+ name,
9
+ className = "",
10
+ onChange,
11
+ checked,
12
+ }) => {
13
+ const handleChange = (e) => {
14
+ const isChecked = e.target.checked;
15
+ onChange(isChecked, id);
16
+ };
17
+
18
+ return (
19
+ <div className={`checkbox-wrapper ${className}`}>
20
+ <input
21
+ id={String(id) || name}
22
+ name={name}
23
+ type="checkbox"
24
+ className="checkbox-input"
25
+ checked={checked}
26
+ onChange={handleChange}
27
+ />
28
+ {label && (
29
+ <label htmlFor={String(id) || name} className="checkbox-label">
30
+ <span className="checkbox-text">{label}</span>
31
+ {subLabel && <p className="checkbox-subtext">{subLabel}</p>}
32
+ </label>
33
+ )}
34
+ </div>
35
+ );
36
+ };
37
+
38
+ export default CheckboxV2;
@@ -0,0 +1,6 @@
1
+ // utils.js
2
+ import getSymbolFromCurrency from 'currency-symbol-map';
3
+
4
+ export const currencySymbol = () => {
5
+ return getSymbolFromCurrency('USD');
6
+ };
@@ -0,0 +1,69 @@
1
+ import React from "react";
2
+ import "../../styles/customdatepicker.scss";
3
+ import { DatePickerInput } from "@mantine/dates";
4
+
5
+ const CustomDatePicker = ({
6
+ label,
7
+ placeholder,
8
+ value,
9
+ onChange,
10
+ minDate,
11
+ maxDate,
12
+ excludeDate,
13
+ }) => {
14
+ return (
15
+ <DatePickerInput
16
+ label={label}
17
+ placeholder={placeholder}
18
+ value={value}
19
+ onChange={onChange}
20
+ minDate={minDate}
21
+ maxDate={maxDate}
22
+ hideOutsideDates
23
+ radius="xl"
24
+ clearable
25
+ valueFormat="MMM DD, YYYY"
26
+ excludeDate={excludeDate}
27
+ style={{ zIndex: 1000 }}
28
+ renderDay={(date) => {
29
+ const today = new Date();
30
+ const isBeforeMinDate = minDate && date < minDate;
31
+ const isAfterMaxDate = maxDate && date > maxDate;
32
+ const isExcluded = excludeDate && excludeDate(date);
33
+
34
+ const isDisabled =
35
+ (isBeforeMinDate || isAfterMaxDate || isExcluded) &&
36
+ !(date.toDateString() === today.toDateString() && !isExcluded);
37
+
38
+ return (
39
+ <div
40
+ style={{
41
+ position: "relative",
42
+ textAlign: "center",
43
+ fontSize: "14px",
44
+ }}
45
+ >
46
+ {date.getDate()}
47
+ {isDisabled && (
48
+ <span
49
+ style={{
50
+ position: "absolute",
51
+ top: "50%",
52
+ left: "50%",
53
+ transform: "translate(-50%, -50%)",
54
+ fontSize: "8px",
55
+ color: "red",
56
+ pointerEvents: "none",
57
+ }}
58
+ >
59
+
60
+ </span>
61
+ )}
62
+ </div>
63
+ );
64
+ }}
65
+ />
66
+ );
67
+ };
68
+
69
+ export default CustomDatePicker;
@@ -0,0 +1,75 @@
1
+ import React from "react";
2
+ import "../../styles/footer.scss";
3
+ import "../../styles/wrapper.scss";
4
+
5
+ const Footer = () => {
6
+ return (
7
+ <footer className="footer">
8
+ <div className="wrapper">
9
+ <div className="footer__container">
10
+ {/* About Section */}
11
+ <div className="footer__section">
12
+ <h3 className="footer__title">ABOUT AGENCY</h3>
13
+ <p className="footer__text">
14
+ The world has become so fast-paced that people don’t want to stand by
15
+ reading a page of information; they would much rather look at a presentation
16
+ and understand the message.
17
+ </p>
18
+ </div>
19
+
20
+ {/* Navigation Links */}
21
+ <div className="footer__section">
22
+ <h3 className="footer__title">NAVIGATION LINKS</h3>
23
+ <ul className="footer__list footer__list--grid">
24
+ {["Home", "Feature", "Services", "Portfolio", "Team", "Pricing", "Blog", "Contact"].map(
25
+ (link, index) => (
26
+ <li key={index} className="footer__list-item">
27
+ {link}
28
+ </li>
29
+ )
30
+ )}
31
+ </ul>
32
+ </div>
33
+
34
+ {/* Newsletter */}
35
+ <div className="footer__section">
36
+ <h3 className="footer__title">NEWSLETTER</h3>
37
+ <p className="footer__text">
38
+ For business professionals caught between high OEM price and mediocre
39
+ print and graphic output.
40
+ </p>
41
+ {/* <div className="footer__newsletter">
42
+ <input type="email" placeholder="Email Address" className="footer__input" />
43
+ <button className="footer__button">📩</button>
44
+ </div> */}
45
+ </div>
46
+
47
+ {/* InstaFeed */}
48
+ <div className="footer__section footer__section--instafeed">
49
+ <h3 className="footer__title">INSTAFEED</h3>
50
+ <div className="footer__instafeed">
51
+ {[44, 45, 46, 47, 48, 49, 51, 60 ].map((imgId, index) => (
52
+ <img
53
+ key={index}
54
+ src={`https://randomuser.me/api/portraits/women/${imgId}.jpg`}
55
+ alt="insta"
56
+ className="footer__instafeed-img"
57
+ />
58
+ ))}
59
+ </div>
60
+ </div>
61
+ </div>
62
+
63
+ {/* Copyright Section */}
64
+ <div className="footer__copyright">
65
+ <br />
66
+ <p>
67
+ ©2025 All rights reserved | This StayCommerce is made with ❤️ by <a href="https://www.w3villa.com/">W3villa.com</a>
68
+ </p>
69
+ </div>
70
+ </div>
71
+ </footer>
72
+ );
73
+ };
74
+
75
+ export default Footer;