From 64af77101fac70e6611f4d7bda4c0c467349c283 Mon Sep 17 00:00:00 2001 From: Husanjonazamov Date: Tue, 24 Feb 2026 12:52:49 +0500 Subject: [PATCH] classify web --- .env | 39 + .gitignore | 37 + .htaccess | 15 + .well-known/apple-app-site-association | 14 + .well-known/assetlinks.json | 26 + HOC/Checkauth.jsx | 59 + api/AxiosInterceptors.jsx | 50 + app/about-us/page.jsx | 48 + app/ad-details/[slug]/page.jsx | 104 + app/ad-listing/page.jsx | 5 + app/ads/page.jsx | 215 + app/blogs/[slug]/page.jsx | 119 + app/blogs/page.jsx | 123 + app/chat/page.jsx | 7 + app/contact-us/page.jsx | 46 + app/edit-listing/[id]/page.jsx | 9 + app/error.jsx | 37 + app/faqs/page.jsx | 45 + app/favorites/page.jsx | 9 + app/globals.css | 274 + app/job-applications/page.jsx | 7 + app/landing/page.jsx | 57 + app/layout.js | 46 + app/loading.jsx | 10 + app/middleware.js | 1 + app/my-ads/page.jsx | 5 + app/my-listing/[slug]/page.jsx | 8 + app/not-found.jsx | 22 + app/notifications/page.jsx | 7 + app/page.js | 202 + app/privacy-policy/page.jsx | 47 + app/profile/page.jsx | 7 + app/refund-policy/page.jsx | 47 + app/reviews/page.jsx | 7 + app/seller/[id]/page.jsx | 98 + app/sitemap.js | 223 + app/subscription/page.jsx | 45 + app/terms-and-condition/page.jsx | 50 + app/transactions/page.jsx | 7 + app/user-subscription/page.jsx | 7 + app/user-verification/page.jsx | 7 + components.json | 21 + .../Auth/DeleteAccountVerifyOtpModal.jsx | 249 + components/Auth/LoginModal.jsx | 382 + components/Auth/LoginWithEmailForm.jsx | 189 + components/Auth/LoginWithMobileForm.jsx | 194 + components/Auth/MailSentSuccessModal.jsx | 36 + components/Auth/OtpScreen.jsx | 244 + components/Auth/RegisterModal.jsx | 180 + components/Auth/RegisterWithEmailForm.jsx | 183 + components/Auth/RegisterWithMobileForm.jsx | 310 + components/Auth/ResetPasswordScreen.jsx | 127 + components/Auth/TermsAndPrivacyLinks.jsx | 26 + components/Auth/UnauthorizedModal.jsx | 39 + components/BreadCrumb/BreadCrumb.jsx | 114 + components/Common/CustomImage.jsx | 42 + components/Common/CustomLink.jsx | 29 + components/Common/Header.jsx | 11 + components/Common/LanguageDropdown.jsx | 218 + components/Common/Loader.jsx | 12 + components/Common/MapComponent.jsx | 89 + components/Common/OpenInAppDrawer.jsx | 83 + components/Common/PageLoader.jsx | 14 + components/Common/Pagination.jsx | 113 + components/Common/ProductCard.jsx | 120 + components/Common/ProductCardSkeleton.jsx | 17 + components/Common/ProductHorizontalCard.jsx | 116 + .../Common/ProductHorizontalCardSkeleton.jsx | 34 + components/Common/ReusableAlertDialog.jsx | 46 + components/Common/ShareDropdown.jsx | 107 + components/Common/useAutoFocus.jsx | 17 + components/Common/useNavigate.jsx | 27 + components/EmptyStates/NoData.jsx | 21 + components/Filter/AreaNode.jsx | 51 + components/Filter/BudgetFilter.jsx | 59 + components/Filter/CategoryNode.jsx | 145 + components/Filter/CityNode.jsx | 158 + components/Filter/CountryNode.jsx | 160 + components/Filter/DatePostedFilter.jsx | 63 + components/Filter/ExtraDetailsFilter.jsx | 155 + components/Filter/Filter.jsx | 118 + components/Filter/FilterTree.jsx | 104 + components/Filter/LocationTree.jsx | 130 + components/Filter/RangeFilter.jsx | 78 + components/Filter/StateNode.jsx | 162 + components/Footer/Footer.jsx | 251 + components/Layout/Layout.jsx | 48 + components/Layout/PushNotificationLayout.jsx | 101 + components/Layout/ScrollToTopButton.jsx | 41 + components/Layout/StructuredData.jsx | 14 + components/Layout/useClientLayoutLogic.jsx | 100 + components/Layout/useGetCategories.jsx | 72 + components/Layout/useGetLocation.jsx | 87 + components/Location/GetLocationWithMap.jsx | 117 + .../LandingAdEditSearchAutocomplete.jsx | 251 + components/Location/LocationModal.jsx | 43 + components/Location/LocationSelector.jsx | 578 + components/Location/Map.jsx | 61 + components/Location/MapLocation.jsx | 193 + components/Location/SearchAutocomplete.jsx | 248 + components/PagesComponent/Ads/Ads.jsx | 817 ++ .../AdsListing/AdLanguageSelector.jsx | 54 + .../AdsListing/AdSuccessModal.jsx | 55 + .../PagesComponent/AdsListing/AdsListing.jsx | 753 ++ .../AdsListing/ComponentFive.jsx | 173 + .../AdsListing/ComponentFour.jsx | 233 + .../AdsListing/ComponentOne.jsx | 81 + .../AdsListing/ComponentThree.jsx | 338 + .../AdsListing/ComponentTwo.jsx | 293 + .../AdsListing/ManualAddress.jsx | 853 ++ .../BlogDetail/BlogDetailPage.jsx | 203 + components/PagesComponent/Blogs/Blogs.jsx | 103 + .../PagesComponent/Blogs/PopularPosts.jsx | 80 + components/PagesComponent/Blogs/Tags.jsx | 82 + .../Cards/AddListingPlanCard.jsx | 228 + .../PagesComponent/Chat/BlockedUsersMenu.jsx | 139 + components/PagesComponent/Chat/Chat.jsx | 173 + components/PagesComponent/Chat/ChatList.jsx | 119 + .../PagesComponent/Chat/ChatListCard.jsx | 62 + .../Chat/ChatListCardSkeleton.jsx | 25 + .../PagesComponent/Chat/ChatMessages.jsx | 343 + components/PagesComponent/Chat/GiveReview.jsx | 173 + .../PagesComponent/Chat/NoChatFound.jsx | 21 + .../PagesComponent/Chat/NoChatListFound.jsx | 23 + .../Chat/SelectedChatHeader.jsx | 137 + .../PagesComponent/Chat/SendMessage.jsx | 256 + .../PagesComponent/Contact/ContactUs.jsx | 380 + .../EditListing/AdsEditSuccessModal.jsx | 53 + .../EditListing/EditComponentFour.jsx | 177 + .../EditListing/EditComponentOne.jsx | 289 + .../EditListing/EditComponentThree.jsx | 298 + .../EditListing/EditComponentTwo.jsx | 322 + .../EditListing/EditListing.jsx | 538 + components/PagesComponent/Faq/FaqCard.jsx | 31 + components/PagesComponent/Faq/FaqsPage.jsx | 57 + .../PagesComponent/Favorites/Favorites.jsx | 95 + components/PagesComponent/Home/AllItems.jsx | 165 + .../PagesComponent/Home/AllItemsSkeleton.jsx | 14 + .../PagesComponent/Home/FeaturedSections.jsx | 62 + .../Home/FeaturedSectionsSkeleton.jsx | 20 + .../PagesComponent/Home/HeaderCategories.jsx | 300 + components/PagesComponent/Home/Home.jsx | 110 + components/PagesComponent/Home/HomeHeader.jsx | 435 + .../PagesComponent/Home/HomeMobileMenu.jsx | 260 + .../PagesComponent/Home/OfferSlider.jsx | 124 + .../Home/OfferSliderSkeleton.jsx | 23 + .../PagesComponent/Home/PopularCategories.jsx | 123 + .../Home/PopularCategoriesSkeleton.jsx | 38 + .../Home/PopularCategoryCard.jsx | 28 + .../PagesComponent/Home/ProfileDropdown.jsx | 121 + components/PagesComponent/Home/Search.jsx | 156 + .../JobApplications/JobApplications.jsx | 150 + .../LandingPage/AnythingYouWant.jsx | 172 + .../PagesComponent/LandingPage/BlogCard.jsx | 37 + .../LandingPage/LandingHeader.jsx | 141 + .../LandingPage/LandingMobileMenu.jsx | 103 + .../PagesComponent/LandingPage/OurBlogs.jsx | 122 + .../LandingPage/QuickAnswers.jsx | 70 + .../LandingPage/WorkProcess.jsx | 56 + .../MyAds/ChoosePackageModal.jsx | 173 + .../PagesComponent/MyAds/GetMyAdStatus.jsx | 75 + components/PagesComponent/MyAds/MyAds.jsx | 437 + components/PagesComponent/MyAds/MyAdsCard.jsx | 162 + .../Notifications/NotificationSkeleton.jsx | 47 + .../Notifications/Notifications.jsx | 134 + .../ProductDetail/AdEditedByAdmin.jsx | 50 + .../ProductDetail/AdsReportCard.jsx | 51 + .../ProductDetail/AdsStatusChangeCards.jsx | 220 + .../ProductDetail/ApplyJobModal.jsx | 267 + .../ProductDetail/JobApplicationCard.jsx | 142 + .../JobApplicationCardSkeleton.jsx | 47 + .../ProductDetail/JobApplicationModal.jsx | 143 + .../ProductDetail/MakeFeaturedAd.jsx | 112 + .../ProductDetail/MakeOfferModal.jsx | 198 + .../ProductDetail/MyAdsListingDetailCard.jsx | 161 + .../ProductDetail/ProductDescription.jsx | 53 + .../ProductDetail/ProductDetailCard.jsx | 95 + .../ProductDetail/ProductDetails.jsx | 264 + .../ProductDetail/ProductFeature.jsx | 80 + .../ProductDetail/ProductGallery.jsx | 205 + .../ProductDetail/ProductLocation.jsx | 50 + .../PagesComponent/ProductDetail/RenewAd.jsx | 116 + .../ProductDetail/SellerDetailCard.jsx | 221 + .../ProductDetail/SimilarProducts.jsx | 97 + .../ProductDetail/SoldOutModal.jsx | 199 + .../ProductDetail/SoldOutModalSkeleton.jsx | 39 + .../ProfileDashboard/ProfileDashboard.jsx | 116 + .../PagesComponent/Reviews/MyReviewsCard.jsx | 126 + .../Reviews/MyReviewsCardSkeleton.jsx | 60 + .../PagesComponent/Reviews/RatingsSummary.jsx | 45 + .../Reviews/RatingsSummarySkeleton.jsx | 31 + .../Reviews/ReportReviewModal.jsx | 109 + components/PagesComponent/Reviews/Reviews.jsx | 90 + .../Reviews/SellerReviewCard.jsx | 70 + .../PagesComponent/Reviews/StarRating.jsx | 38 + components/PagesComponent/Seller/Seller.jsx | 141 + .../Seller/SellerDetailCard.jsx | 114 + .../PagesComponent/Seller/SellerLsitings.jsx | 200 + .../PagesComponent/Seller/SellerRating.jsx | 39 + .../PagesComponent/Seller/SellerSkeleton.jsx | 75 + .../PagesComponent/StaticPages/AboutUs.jsx | 22 + .../StaticPages/PrivacyPolicy.jsx | 26 + .../StaticPages/RefundPolicy.jsx | 26 + .../StaticPages/TermsAndCondition.jsx | 23 + .../Subscription/BankDetailsModal.jsx | 120 + .../Subscription/BankTransferPayment.jsx | 24 + .../Subscription/FlutterwavePayment.jsx | 77 + .../Subscription/PayStackPayment.jsx | 79 + .../Subscription/PaymentModal.jsx | 146 + .../Subscription/PaymentModalLoading.jsx | 22 + .../Subscription/PaypalPayment.jsx | 79 + .../Subscription/PhonepePayment.jsx | 88 + .../Subscription/ProfileSubscription.jsx | 224 + .../Subscription/RazorpayPayment.jsx | 109 + .../Subscription/StripePayment.jsx | 179 + .../Subscription/Subscription.jsx | 234 + .../Transactions/Transactions.jsx | 150 + .../Transactions/UploadReceiptModal.jsx | 136 + .../UserVerification/UserVerification.jsx | 463 + components/Profile/Profile.jsx | 428 + components/Profile/ProfileSidebar.jsx | 235 + .../AdListingPublicPlanCardSkeleton.jsx | 50 + .../Skeletons/AddListingPlanCardSkeleton.jsx | 50 + components/Skeletons/BlogCardSkeleton.jsx | 15 + .../Skeletons/JobApplicationSkeleton.jsx | 63 + components/Skeletons/TransactionSkeleton.jsx | 67 + components/User/ReportModal.jsx | 148 + components/ui/accordion.jsx | 44 + components/ui/alert-dialog.jsx | 99 + components/ui/alert.jsx | 47 + components/ui/badge.jsx | 34 + components/ui/breadcrumb.jsx | 92 + components/ui/button.jsx | 50 + components/ui/card.jsx | 50 + components/ui/carousel.jsx | 226 + components/ui/checkbox.jsx | 24 + components/ui/collapsible.jsx | 11 + components/ui/command.jsx | 135 + components/ui/context-menu.jsx | 158 + components/ui/dialog.jsx | 106 + components/ui/drawer.jsx | 92 + components/ui/dropdown-menu.jsx | 157 + components/ui/input.jsx | 19 + components/ui/label.jsx | 22 + components/ui/navigation-menu.jsx | 104 + components/ui/pagination.jsx | 100 + components/ui/popover.jsx | 27 + components/ui/progress.jsx | 29 + components/ui/radio-group.jsx | 31 + components/ui/scroll-area.jsx | 40 + components/ui/select.jsx | 122 + components/ui/separator.jsx | 25 + components/ui/sheet.jsx | 110 + components/ui/skeleton.jsx | 10 + components/ui/slider.jsx | 25 + components/ui/sonner.jsx | 29 + components/ui/switch.jsx | 24 + components/ui/table.jsx | 83 + components/ui/tabs.jsx | 43 + components/ui/textarea.jsx | 18 + components/ui/tooltip.jsx | 26 + install.sh | 85 + jsconfig.json | 38 + lib/constants.js | 5 + lib/utils.js | 8 + next.config.mjs | 18 + package-lock.json | 9913 +++++++++++++++++ package.json | 81 + postcss.config.mjs | 8 + public/assets/Arrow.svg | 14 + public/assets/Google Download.png | Bin 0 -> 11803 bytes public/assets/Image1.png | Bin 0 -> 58444 bytes public/assets/Image2.png | Bin 0 -> 72135 bytes public/assets/Image3.png | Bin 0 -> 84105 bytes public/assets/Image4.png | Bin 0 -> 90374 bytes public/assets/Image5.png | Bin 0 -> 65913 bytes public/assets/Image6.png | Bin 0 -> 77091 bytes public/assets/Mail Verification.svg | 56 + public/assets/NewBG.png | Bin 0 -> 414696 bytes public/assets/Transperant_Placeholder.png | Bin 0 -> 4375 bytes public/assets/ad_icon.svg | 22 + public/assets/flutterwave.png | Bin 0 -> 1418 bytes public/assets/iOS Download.png | Bin 0 -> 11119 bytes public/assets/ic_paystack.png | Bin 0 -> 401 bytes public/assets/ic_razorpay.png | Bin 0 -> 743 bytes public/assets/ic_stripe.png | Bin 0 -> 651 bytes public/assets/no_data_found_illustrator.svg | 93 + public/assets/paypal-logo.png | Bin 0 -> 51877 bytes public/assets/phonepe-icon.png | Bin 0 -> 26040 bytes public/assets/something_went_wrong.svg | 222 + public/assets/true.gif | Bin 0 -> 293974 bytes public/firebase-messaging-sw.js | 24 + redux/reducer/authSlice.js | 51 + redux/reducer/breadCrumbSlice.js | 30 + redux/reducer/categorySlice.js | 61 + redux/reducer/globalStateSlice.js | 134 + redux/reducer/languageSlice.js | 39 + redux/reducer/locationSlice.js | 74 + redux/reducer/settingSlice.js | 137 + redux/store/index.js | 40 + redux/store/providers.jsx | 6 + server.js | 32 + tailwind.config.js | 121 + utils/Firebase.js | 121 + utils/api.js | 1180 ++ utils/constants.jsx | 51 + utils/generateKeywords.js | 29 + utils/getFetcherStatus.js | 14 + utils/index.jsx | 1337 +++ utils/locale/en.json | 742 ++ 310 files changed, 45449 insertions(+) create mode 100644 .env create mode 100644 .gitignore create mode 100644 .htaccess create mode 100644 .well-known/apple-app-site-association create mode 100644 .well-known/assetlinks.json create mode 100644 HOC/Checkauth.jsx create mode 100644 api/AxiosInterceptors.jsx create mode 100644 app/about-us/page.jsx create mode 100644 app/ad-details/[slug]/page.jsx create mode 100644 app/ad-listing/page.jsx create mode 100644 app/ads/page.jsx create mode 100644 app/blogs/[slug]/page.jsx create mode 100644 app/blogs/page.jsx create mode 100644 app/chat/page.jsx create mode 100644 app/contact-us/page.jsx create mode 100644 app/edit-listing/[id]/page.jsx create mode 100644 app/error.jsx create mode 100644 app/faqs/page.jsx create mode 100644 app/favorites/page.jsx create mode 100644 app/globals.css create mode 100644 app/job-applications/page.jsx create mode 100644 app/landing/page.jsx create mode 100644 app/layout.js create mode 100644 app/loading.jsx create mode 100644 app/middleware.js create mode 100644 app/my-ads/page.jsx create mode 100644 app/my-listing/[slug]/page.jsx create mode 100644 app/not-found.jsx create mode 100644 app/notifications/page.jsx create mode 100644 app/page.js create mode 100644 app/privacy-policy/page.jsx create mode 100644 app/profile/page.jsx create mode 100644 app/refund-policy/page.jsx create mode 100644 app/reviews/page.jsx create mode 100644 app/seller/[id]/page.jsx create mode 100644 app/sitemap.js create mode 100644 app/subscription/page.jsx create mode 100644 app/terms-and-condition/page.jsx create mode 100644 app/transactions/page.jsx create mode 100644 app/user-subscription/page.jsx create mode 100644 app/user-verification/page.jsx create mode 100644 components.json create mode 100644 components/Auth/DeleteAccountVerifyOtpModal.jsx create mode 100644 components/Auth/LoginModal.jsx create mode 100644 components/Auth/LoginWithEmailForm.jsx create mode 100644 components/Auth/LoginWithMobileForm.jsx create mode 100644 components/Auth/MailSentSuccessModal.jsx create mode 100644 components/Auth/OtpScreen.jsx create mode 100644 components/Auth/RegisterModal.jsx create mode 100644 components/Auth/RegisterWithEmailForm.jsx create mode 100644 components/Auth/RegisterWithMobileForm.jsx create mode 100644 components/Auth/ResetPasswordScreen.jsx create mode 100644 components/Auth/TermsAndPrivacyLinks.jsx create mode 100644 components/Auth/UnauthorizedModal.jsx create mode 100644 components/BreadCrumb/BreadCrumb.jsx create mode 100644 components/Common/CustomImage.jsx create mode 100644 components/Common/CustomLink.jsx create mode 100644 components/Common/Header.jsx create mode 100644 components/Common/LanguageDropdown.jsx create mode 100644 components/Common/Loader.jsx create mode 100644 components/Common/MapComponent.jsx create mode 100644 components/Common/OpenInAppDrawer.jsx create mode 100644 components/Common/PageLoader.jsx create mode 100644 components/Common/Pagination.jsx create mode 100644 components/Common/ProductCard.jsx create mode 100644 components/Common/ProductCardSkeleton.jsx create mode 100644 components/Common/ProductHorizontalCard.jsx create mode 100644 components/Common/ProductHorizontalCardSkeleton.jsx create mode 100644 components/Common/ReusableAlertDialog.jsx create mode 100644 components/Common/ShareDropdown.jsx create mode 100644 components/Common/useAutoFocus.jsx create mode 100644 components/Common/useNavigate.jsx create mode 100644 components/EmptyStates/NoData.jsx create mode 100644 components/Filter/AreaNode.jsx create mode 100644 components/Filter/BudgetFilter.jsx create mode 100644 components/Filter/CategoryNode.jsx create mode 100644 components/Filter/CityNode.jsx create mode 100644 components/Filter/CountryNode.jsx create mode 100644 components/Filter/DatePostedFilter.jsx create mode 100644 components/Filter/ExtraDetailsFilter.jsx create mode 100644 components/Filter/Filter.jsx create mode 100644 components/Filter/FilterTree.jsx create mode 100644 components/Filter/LocationTree.jsx create mode 100644 components/Filter/RangeFilter.jsx create mode 100644 components/Filter/StateNode.jsx create mode 100644 components/Footer/Footer.jsx create mode 100644 components/Layout/Layout.jsx create mode 100644 components/Layout/PushNotificationLayout.jsx create mode 100644 components/Layout/ScrollToTopButton.jsx create mode 100644 components/Layout/StructuredData.jsx create mode 100644 components/Layout/useClientLayoutLogic.jsx create mode 100644 components/Layout/useGetCategories.jsx create mode 100644 components/Layout/useGetLocation.jsx create mode 100644 components/Location/GetLocationWithMap.jsx create mode 100644 components/Location/LandingAdEditSearchAutocomplete.jsx create mode 100644 components/Location/LocationModal.jsx create mode 100644 components/Location/LocationSelector.jsx create mode 100644 components/Location/Map.jsx create mode 100644 components/Location/MapLocation.jsx create mode 100644 components/Location/SearchAutocomplete.jsx create mode 100644 components/PagesComponent/Ads/Ads.jsx create mode 100644 components/PagesComponent/AdsListing/AdLanguageSelector.jsx create mode 100644 components/PagesComponent/AdsListing/AdSuccessModal.jsx create mode 100644 components/PagesComponent/AdsListing/AdsListing.jsx create mode 100644 components/PagesComponent/AdsListing/ComponentFive.jsx create mode 100644 components/PagesComponent/AdsListing/ComponentFour.jsx create mode 100644 components/PagesComponent/AdsListing/ComponentOne.jsx create mode 100644 components/PagesComponent/AdsListing/ComponentThree.jsx create mode 100644 components/PagesComponent/AdsListing/ComponentTwo.jsx create mode 100644 components/PagesComponent/AdsListing/ManualAddress.jsx create mode 100644 components/PagesComponent/BlogDetail/BlogDetailPage.jsx create mode 100644 components/PagesComponent/Blogs/Blogs.jsx create mode 100644 components/PagesComponent/Blogs/PopularPosts.jsx create mode 100644 components/PagesComponent/Blogs/Tags.jsx create mode 100644 components/PagesComponent/Cards/AddListingPlanCard.jsx create mode 100644 components/PagesComponent/Chat/BlockedUsersMenu.jsx create mode 100644 components/PagesComponent/Chat/Chat.jsx create mode 100644 components/PagesComponent/Chat/ChatList.jsx create mode 100644 components/PagesComponent/Chat/ChatListCard.jsx create mode 100644 components/PagesComponent/Chat/ChatListCardSkeleton.jsx create mode 100644 components/PagesComponent/Chat/ChatMessages.jsx create mode 100644 components/PagesComponent/Chat/GiveReview.jsx create mode 100644 components/PagesComponent/Chat/NoChatFound.jsx create mode 100644 components/PagesComponent/Chat/NoChatListFound.jsx create mode 100644 components/PagesComponent/Chat/SelectedChatHeader.jsx create mode 100644 components/PagesComponent/Chat/SendMessage.jsx create mode 100644 components/PagesComponent/Contact/ContactUs.jsx create mode 100644 components/PagesComponent/EditListing/AdsEditSuccessModal.jsx create mode 100644 components/PagesComponent/EditListing/EditComponentFour.jsx create mode 100644 components/PagesComponent/EditListing/EditComponentOne.jsx create mode 100644 components/PagesComponent/EditListing/EditComponentThree.jsx create mode 100644 components/PagesComponent/EditListing/EditComponentTwo.jsx create mode 100644 components/PagesComponent/EditListing/EditListing.jsx create mode 100644 components/PagesComponent/Faq/FaqCard.jsx create mode 100644 components/PagesComponent/Faq/FaqsPage.jsx create mode 100644 components/PagesComponent/Favorites/Favorites.jsx create mode 100644 components/PagesComponent/Home/AllItems.jsx create mode 100644 components/PagesComponent/Home/AllItemsSkeleton.jsx create mode 100644 components/PagesComponent/Home/FeaturedSections.jsx create mode 100644 components/PagesComponent/Home/FeaturedSectionsSkeleton.jsx create mode 100644 components/PagesComponent/Home/HeaderCategories.jsx create mode 100644 components/PagesComponent/Home/Home.jsx create mode 100644 components/PagesComponent/Home/HomeHeader.jsx create mode 100644 components/PagesComponent/Home/HomeMobileMenu.jsx create mode 100644 components/PagesComponent/Home/OfferSlider.jsx create mode 100644 components/PagesComponent/Home/OfferSliderSkeleton.jsx create mode 100644 components/PagesComponent/Home/PopularCategories.jsx create mode 100644 components/PagesComponent/Home/PopularCategoriesSkeleton.jsx create mode 100644 components/PagesComponent/Home/PopularCategoryCard.jsx create mode 100644 components/PagesComponent/Home/ProfileDropdown.jsx create mode 100644 components/PagesComponent/Home/Search.jsx create mode 100644 components/PagesComponent/JobApplications/JobApplications.jsx create mode 100644 components/PagesComponent/LandingPage/AnythingYouWant.jsx create mode 100644 components/PagesComponent/LandingPage/BlogCard.jsx create mode 100644 components/PagesComponent/LandingPage/LandingHeader.jsx create mode 100644 components/PagesComponent/LandingPage/LandingMobileMenu.jsx create mode 100644 components/PagesComponent/LandingPage/OurBlogs.jsx create mode 100644 components/PagesComponent/LandingPage/QuickAnswers.jsx create mode 100644 components/PagesComponent/LandingPage/WorkProcess.jsx create mode 100644 components/PagesComponent/MyAds/ChoosePackageModal.jsx create mode 100644 components/PagesComponent/MyAds/GetMyAdStatus.jsx create mode 100644 components/PagesComponent/MyAds/MyAds.jsx create mode 100644 components/PagesComponent/MyAds/MyAdsCard.jsx create mode 100644 components/PagesComponent/Notifications/NotificationSkeleton.jsx create mode 100644 components/PagesComponent/Notifications/Notifications.jsx create mode 100644 components/PagesComponent/ProductDetail/AdEditedByAdmin.jsx create mode 100644 components/PagesComponent/ProductDetail/AdsReportCard.jsx create mode 100644 components/PagesComponent/ProductDetail/AdsStatusChangeCards.jsx create mode 100644 components/PagesComponent/ProductDetail/ApplyJobModal.jsx create mode 100644 components/PagesComponent/ProductDetail/JobApplicationCard.jsx create mode 100644 components/PagesComponent/ProductDetail/JobApplicationCardSkeleton.jsx create mode 100644 components/PagesComponent/ProductDetail/JobApplicationModal.jsx create mode 100644 components/PagesComponent/ProductDetail/MakeFeaturedAd.jsx create mode 100644 components/PagesComponent/ProductDetail/MakeOfferModal.jsx create mode 100644 components/PagesComponent/ProductDetail/MyAdsListingDetailCard.jsx create mode 100644 components/PagesComponent/ProductDetail/ProductDescription.jsx create mode 100644 components/PagesComponent/ProductDetail/ProductDetailCard.jsx create mode 100644 components/PagesComponent/ProductDetail/ProductDetails.jsx create mode 100644 components/PagesComponent/ProductDetail/ProductFeature.jsx create mode 100644 components/PagesComponent/ProductDetail/ProductGallery.jsx create mode 100644 components/PagesComponent/ProductDetail/ProductLocation.jsx create mode 100644 components/PagesComponent/ProductDetail/RenewAd.jsx create mode 100644 components/PagesComponent/ProductDetail/SellerDetailCard.jsx create mode 100644 components/PagesComponent/ProductDetail/SimilarProducts.jsx create mode 100644 components/PagesComponent/ProductDetail/SoldOutModal.jsx create mode 100644 components/PagesComponent/ProductDetail/SoldOutModalSkeleton.jsx create mode 100644 components/PagesComponent/ProfileDashboard/ProfileDashboard.jsx create mode 100644 components/PagesComponent/Reviews/MyReviewsCard.jsx create mode 100644 components/PagesComponent/Reviews/MyReviewsCardSkeleton.jsx create mode 100644 components/PagesComponent/Reviews/RatingsSummary.jsx create mode 100644 components/PagesComponent/Reviews/RatingsSummarySkeleton.jsx create mode 100644 components/PagesComponent/Reviews/ReportReviewModal.jsx create mode 100644 components/PagesComponent/Reviews/Reviews.jsx create mode 100644 components/PagesComponent/Reviews/SellerReviewCard.jsx create mode 100644 components/PagesComponent/Reviews/StarRating.jsx create mode 100644 components/PagesComponent/Seller/Seller.jsx create mode 100644 components/PagesComponent/Seller/SellerDetailCard.jsx create mode 100644 components/PagesComponent/Seller/SellerLsitings.jsx create mode 100644 components/PagesComponent/Seller/SellerRating.jsx create mode 100644 components/PagesComponent/Seller/SellerSkeleton.jsx create mode 100644 components/PagesComponent/StaticPages/AboutUs.jsx create mode 100644 components/PagesComponent/StaticPages/PrivacyPolicy.jsx create mode 100644 components/PagesComponent/StaticPages/RefundPolicy.jsx create mode 100644 components/PagesComponent/StaticPages/TermsAndCondition.jsx create mode 100644 components/PagesComponent/Subscription/BankDetailsModal.jsx create mode 100644 components/PagesComponent/Subscription/BankTransferPayment.jsx create mode 100644 components/PagesComponent/Subscription/FlutterwavePayment.jsx create mode 100644 components/PagesComponent/Subscription/PayStackPayment.jsx create mode 100644 components/PagesComponent/Subscription/PaymentModal.jsx create mode 100644 components/PagesComponent/Subscription/PaymentModalLoading.jsx create mode 100644 components/PagesComponent/Subscription/PaypalPayment.jsx create mode 100644 components/PagesComponent/Subscription/PhonepePayment.jsx create mode 100644 components/PagesComponent/Subscription/ProfileSubscription.jsx create mode 100644 components/PagesComponent/Subscription/RazorpayPayment.jsx create mode 100644 components/PagesComponent/Subscription/StripePayment.jsx create mode 100644 components/PagesComponent/Subscription/Subscription.jsx create mode 100644 components/PagesComponent/Transactions/Transactions.jsx create mode 100644 components/PagesComponent/Transactions/UploadReceiptModal.jsx create mode 100644 components/PagesComponent/UserVerification/UserVerification.jsx create mode 100644 components/Profile/Profile.jsx create mode 100644 components/Profile/ProfileSidebar.jsx create mode 100644 components/Skeletons/AdListingPublicPlanCardSkeleton.jsx create mode 100644 components/Skeletons/AddListingPlanCardSkeleton.jsx create mode 100644 components/Skeletons/BlogCardSkeleton.jsx create mode 100644 components/Skeletons/JobApplicationSkeleton.jsx create mode 100644 components/Skeletons/TransactionSkeleton.jsx create mode 100644 components/User/ReportModal.jsx create mode 100644 components/ui/accordion.jsx create mode 100644 components/ui/alert-dialog.jsx create mode 100644 components/ui/alert.jsx create mode 100644 components/ui/badge.jsx create mode 100644 components/ui/breadcrumb.jsx create mode 100644 components/ui/button.jsx create mode 100644 components/ui/card.jsx create mode 100644 components/ui/carousel.jsx create mode 100644 components/ui/checkbox.jsx create mode 100644 components/ui/collapsible.jsx create mode 100644 components/ui/command.jsx create mode 100644 components/ui/context-menu.jsx create mode 100644 components/ui/dialog.jsx create mode 100644 components/ui/drawer.jsx create mode 100644 components/ui/dropdown-menu.jsx create mode 100644 components/ui/input.jsx create mode 100644 components/ui/label.jsx create mode 100644 components/ui/navigation-menu.jsx create mode 100644 components/ui/pagination.jsx create mode 100644 components/ui/popover.jsx create mode 100644 components/ui/progress.jsx create mode 100644 components/ui/radio-group.jsx create mode 100644 components/ui/scroll-area.jsx create mode 100644 components/ui/select.jsx create mode 100644 components/ui/separator.jsx create mode 100644 components/ui/sheet.jsx create mode 100644 components/ui/skeleton.jsx create mode 100644 components/ui/slider.jsx create mode 100644 components/ui/sonner.jsx create mode 100644 components/ui/switch.jsx create mode 100644 components/ui/table.jsx create mode 100644 components/ui/tabs.jsx create mode 100644 components/ui/textarea.jsx create mode 100644 components/ui/tooltip.jsx create mode 100644 install.sh create mode 100644 jsconfig.json create mode 100644 lib/constants.js create mode 100644 lib/utils.js create mode 100644 next.config.mjs create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.mjs create mode 100644 public/assets/Arrow.svg create mode 100644 public/assets/Google Download.png create mode 100644 public/assets/Image1.png create mode 100644 public/assets/Image2.png create mode 100644 public/assets/Image3.png create mode 100644 public/assets/Image4.png create mode 100644 public/assets/Image5.png create mode 100644 public/assets/Image6.png create mode 100644 public/assets/Mail Verification.svg create mode 100644 public/assets/NewBG.png create mode 100644 public/assets/Transperant_Placeholder.png create mode 100644 public/assets/ad_icon.svg create mode 100644 public/assets/flutterwave.png create mode 100644 public/assets/iOS Download.png create mode 100644 public/assets/ic_paystack.png create mode 100644 public/assets/ic_razorpay.png create mode 100644 public/assets/ic_stripe.png create mode 100644 public/assets/no_data_found_illustrator.svg create mode 100644 public/assets/paypal-logo.png create mode 100644 public/assets/phonepe-icon.png create mode 100644 public/assets/something_went_wrong.svg create mode 100644 public/assets/true.gif create mode 100644 public/firebase-messaging-sw.js create mode 100644 redux/reducer/authSlice.js create mode 100644 redux/reducer/breadCrumbSlice.js create mode 100644 redux/reducer/categorySlice.js create mode 100644 redux/reducer/globalStateSlice.js create mode 100644 redux/reducer/languageSlice.js create mode 100644 redux/reducer/locationSlice.js create mode 100644 redux/reducer/settingSlice.js create mode 100644 redux/store/index.js create mode 100644 redux/store/providers.jsx create mode 100644 server.js create mode 100644 tailwind.config.js create mode 100644 utils/Firebase.js create mode 100644 utils/api.js create mode 100644 utils/constants.jsx create mode 100644 utils/generateKeywords.js create mode 100644 utils/getFetcherStatus.js create mode 100644 utils/index.jsx create mode 100644 utils/locale/en.json diff --git a/.env b/.env new file mode 100644 index 0000000..886ac39 --- /dev/null +++ b/.env @@ -0,0 +1,39 @@ +# Web Version (Do not Change) +NEXT_PUBLIC_WEB_VERSION="2.10.1" + + +# Admin panle url +NEXT_PUBLIC_API_URL="https://eclassify.wrteam.me" + + +# Website URL +NEXT_PUBLIC_WEB_URL="https://eclassifyweb.wrteam.me" + +# API ENDPOINT (Do not change) +NEXT_PUBLIC_END_POINT="/api/" + +# Firebase config +NEXT_PUBLIC_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +NEXT_PUBLIC_AUTH_DOMAIN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +NEXT_PUBLIC_PROJECT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +NEXT_PUBLIC_STORAGE_BUCKET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +NEXT_PUBLIC_MESSAGING_SENDER_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +NEXT_PUBLIC_APP_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +NEXT_PUBLIC_MEASUREMENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + + +# Vapid api key +NEXT_PUBLIC_VAPID_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +# here you get default country list (https://developers.google.com/hotels/hotel-prices/dev-guide/country-codes) +# enter in small case like (india :- in) +#DEFAULT COUNTRY +NEXT_PUBLIC_DEFAULT_COUNTRY=in +NEXT_PUBLIC_SEO = true + +NEXT_PUBLIC_SEO_REVALIDATE_MINUTES = 60 + +NEXT_PUBLIC_META_TITLE="eClassify - Buy & Sell Marketplace | Find Everything You Need" +NEXT_PUBLIC_META_DESCRIPTION="Discover eClassify, your ultimate online marketplace for buying and selling a wide range of products. Enjoy a seamless shopping experience with diverse listings, secure transactions, and excellent customer support. Join eClassify today and start exploring!" +NEXT_PUBLIC_META_kEYWORDS="buy and sell marketplace, online marketplace, eClassify, buy and sell online, online shopping, sell products online, buy products online, secure transactions, online listings, customer support, e-commerce, digital marketplace, shop online, sell online, online buying and selling" + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be724ac --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ +/public/sitemap.xml + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts \ No newline at end of file diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..ecf77b7 --- /dev/null +++ b/.htaccess @@ -0,0 +1,15 @@ + + RewriteEngine On + RewriteBase / + + RewriteRule ^/.well-known/acme-challenge/(.*) /.well-known/acme-challenge/$1 [L] + + RewriteRule ^_next/(.*) /.next/$1 [L] + # Allow access to static files with specific extensions + RewriteCond %{REQUEST_URI} \.(js|css|svg|jpg|jpeg|png|gif|ico|woff2)$ + RewriteRule ^ - [L] + + RewriteRule ^index.html http://127.0.0.1:8004/$1 [P] + RewriteRule ^index.php http://127.0.0.1:8004/$1 [P] + RewriteRule ^/?(.*)$ http://127.0.0.1:8004/$1 [P] + \ No newline at end of file diff --git a/.well-known/apple-app-site-association b/.well-known/apple-app-site-association new file mode 100644 index 0000000..43a771e --- /dev/null +++ b/.well-known/apple-app-site-association @@ -0,0 +1,14 @@ +{ + "applinks": { + "apps": [], + "details": [ + { + "appID": "QA5UX5B4B6.com.eclassify.wrteam", + "paths": [ + "/ad-details/*", + "/seller/*" + ] + } + ] + } +} \ No newline at end of file diff --git a/.well-known/assetlinks.json b/.well-known/assetlinks.json new file mode 100644 index 0000000..146c2a3 --- /dev/null +++ b/.well-known/assetlinks.json @@ -0,0 +1,26 @@ +[ + { + "relation": [ + "delegate_permission/common.handle_all_urls" + ], + "target": { + "namespace": "android_app", + "package_name": "com.eclassify.wrteam", + "sha256_cert_fingerprints": [ + "B4:B3:AD:26:FA:94:07:B0:EA:CC:30:7E:65:B3:AB:14:B9:98:BB:AB:2F:2C:FF:81:73:9A:6C:22:DF:7C:8C:42" + ] + } + }, + { + "relation": [ + "delegate_permission/common.handle_all_urls" + ], + "target": { + "namespace": "android_app", + "package_name": "com.eclassify.wrteam", + "sha256_cert_fingerprints": [ + "C8:7B:75:BD:A2:AF:6B:E2:93:50:AA:20:43:83:68:DE:AE:87:4B:1C:7A:B3:17:9E:CA:53:F9:BC:A7:9B:F2:39" + ] + } + } +] \ No newline at end of file diff --git a/HOC/Checkauth.jsx b/HOC/Checkauth.jsx new file mode 100644 index 0000000..5e250e4 --- /dev/null +++ b/HOC/Checkauth.jsx @@ -0,0 +1,59 @@ +"use client"; +import { useEffect, useState } from "react"; +import { useSelector } from "react-redux"; +import Loader from "@/components/Common/Loader"; +import { usePathname } from "next/navigation"; +import { useNavigate } from "@/components/Common/useNavigate"; + +const Checkauth = (WrappedComponent) => { + const Wrapper = (props) => { + const pathname = usePathname(); + const { navigate } = useNavigate(); + const user = useSelector((state) => state.UserSignup.data); + const [isAuthorized, setIsAuthorized] = useState(false); + const [authChecked, setAuthChecked] = useState(false); + + useEffect(() => { + // List of routes that require authentication + const privateRoutes = [ + "/profile", + "/ad-listing", + "/notifications", + "/chat", + "/user-subscription", + "/my-ads", + "/favorites", + "/transactions", + "/reviews", + "/edit-listing", + "/user-verification", + "/job-applications", + ]; + const isPrivateRoute = privateRoutes.some( + (route) => pathname === route || pathname.startsWith(`${route}/`) + ); + + // If it's a private route and user is not authenticated + if (isPrivateRoute && !user) { + navigate("/"); + return; + } + + // If user is authenticated or it's not a private route + setIsAuthorized(true); + setAuthChecked(true); + }, [user, pathname]); + + // Show loader until auth check completes + if (!authChecked) { + return ; + } + + // Only render the component if user is authorized + return isAuthorized ? : null; + }; + + return Wrapper; +}; + +export default Checkauth; diff --git a/api/AxiosInterceptors.jsx b/api/AxiosInterceptors.jsx new file mode 100644 index 0000000..120d087 --- /dev/null +++ b/api/AxiosInterceptors.jsx @@ -0,0 +1,50 @@ +import { logoutSuccess } from "@/redux/reducer/authSlice"; +import { setIsUnauthorized } from "@/redux/reducer/globalStateSlice"; +import { store } from "@/redux/store"; +import axios from "axios"; + +const Api = axios.create({ + baseURL: `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}`, +}); + +let isUnauthorizedToastShown = false; + +Api.interceptors.request.use(function (config) { + let token = undefined; + let langCode = undefined; + + if (typeof window !== "undefined") { + const state = store.getState(); + token = state?.UserSignup?.data?.token; + langCode = state?.CurrentLanguage?.language?.code; + } + + if (token) config.headers.authorization = `Bearer ${token}`; + if (langCode) config.headers["Content-Language"] = langCode; + + return config; +}); + +// Add a response interceptor +Api.interceptors.response.use( + function (response) { + return response; + }, + function (error) { + if (error.response && error.response.status === 401) { + // Call the logout function if the status code is 401 + logoutSuccess(); + if (!isUnauthorizedToastShown) { + store.dispatch(setIsUnauthorized(true)); + isUnauthorizedToastShown = true; + // Reset the flag after a certain period + setTimeout(() => { + isUnauthorizedToastShown = false; + }, 3000); // 3 seconds delay before allowing another toast + } + } + return Promise.reject(error); + } +); + +export default Api; diff --git a/app/about-us/page.jsx b/app/about-us/page.jsx new file mode 100644 index 0000000..b09f3d8 --- /dev/null +++ b/app/about-us/page.jsx @@ -0,0 +1,48 @@ +import AboutUs from "@/components/PagesComponent/StaticPages/AboutUs"; +import { SEO_REVALIDATE_SECONDS } from "@/lib/constants"; + +export const dynamic = "force-dynamic"; + + +export const generateMetadata = async ({ searchParams }) => { + try { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + const params = await searchParams; + const langCode = params?.lang || "en"; + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=about-us`, + { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + } + ); + + const data = await res.json(); + const aboutUs = data?.data?.[0]; + + return { + title: aboutUs?.translated_title || process.env.NEXT_PUBLIC_META_TITLE, + description: + aboutUs?.translated_description || + process.env.NEXT_PUBLIC_META_DESCRIPTION, + openGraph: { + images: aboutUs?.image ? [aboutUs?.image] : [], + }, + keywords: + aboutUs?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS, + }; + } catch (error) { + console.error("Error fetching MetaData:", error); + return null; + } +}; + +const AboutUsPage = () => { + return ; +}; + +export default AboutUsPage; diff --git a/app/ad-details/[slug]/page.jsx b/app/ad-details/[slug]/page.jsx new file mode 100644 index 0000000..f4b9b2e --- /dev/null +++ b/app/ad-details/[slug]/page.jsx @@ -0,0 +1,104 @@ +import StructuredData from "@/components/Layout/StructuredData"; +import ProductDetail from "@/components/PagesComponent/ProductDetail/ProductDetails"; +import { SEO_REVALIDATE_SECONDS } from "@/lib/constants"; +import { generateKeywords } from "@/utils/generateKeywords"; + +export const generateMetadata = async ({ params, searchParams }) => { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + try { + const { slug } = await params; + const langCode = (await searchParams)?.lang || "en"; + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-item?slug=${slug}`, + { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + } + ); + + const data = await res.json(); + const item = data?.data?.data?.[0]; + const title = item?.translated_item?.name; + const description = item?.translated_item?.description; + const keywords = generateKeywords(item?.translated_item?.description); + const image = item?.image; + + return { + title: title || process.env.NEXT_PUBLIC_META_TITLE, + description: description || process.env.NEXT_PUBLIC_META_DESCRIPTION, + openGraph: { + images: image ? [image] : [], + }, + keywords: keywords, + }; + } catch (error) { + console.error("Error fetching MetaData:", error); + return null; + } +}; + +const getItemData = async (slug, langCode) => { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + try { + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-item?slug=${slug}`, + { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + } + ); + + const data = await res.json(); + const item = data?.data?.data?.[0]; + return item; + } catch (error) { + console.error("Error fetching item data:", error); + return null; + } +}; + +const ProductDetailPage = async ({ params, searchParams }) => { + const { slug } = await params; + const langCode = (await searchParams).lang || "en"; + const product = await getItemData(slug, langCode); + const jsonLd = product + ? { + "@context": "https://schema.org", + "@type": "Product", + productID: product?.id, + name: product?.translated_item?.name, + description: product?.translated_item?.description, + image: product?.image, + url: `${process.env.NEXT_PUBLIC_WEB_URL}/ad-details/${product?.slug}`, + category: { + "@type": "Thing", + name: product?.category?.translated_name || "General Category", // Default category name + }, + ...(product?.price && { + offers: { + "@type": "Offer", + price: product.price, + priceCurrency: "USD", + }, + }), + countryOfOrigin: product?.translated_item?.country, + } + : null; + + return ( + <> + + + + ); +}; + +export default ProductDetailPage; diff --git a/app/ad-listing/page.jsx b/app/ad-listing/page.jsx new file mode 100644 index 0000000..d31b559 --- /dev/null +++ b/app/ad-listing/page.jsx @@ -0,0 +1,5 @@ +import AdsListing from "@/components/PagesComponent/AdsListing/AdsListing"; +const AdListingPage = () => { + return ; +}; +export default AdListingPage; diff --git a/app/ads/page.jsx b/app/ads/page.jsx new file mode 100644 index 0000000..fb95673 --- /dev/null +++ b/app/ads/page.jsx @@ -0,0 +1,215 @@ +import StructuredData from "@/components/Layout/StructuredData"; +import Products from "@/components/PagesComponent/Ads/Ads"; +import { SEO_REVALIDATE_SECONDS } from "@/lib/constants"; +import { generateKeywords } from "@/utils/generateKeywords"; + +export const dynamic = "force-dynamic"; + + +const buildIndexableParams = (searchParams) => { + const indexableFilters = [ + "category", + "query", + "country", + "state", + "city", + "areaId", + "sortBy", + "min_price", + "max_price", + "date_posted", + ]; + + const params = new URLSearchParams(); + + const { country, state, city, areaId } = searchParams || {}; + + const locationPriority = areaId + ? "areaId" + : city + ? "city" + : state + ? "state" + : country + ? "country" + : null; + + indexableFilters.forEach((key) => { + let value = searchParams[key]; + if (value === undefined || value === "") return; + + // 🧹 Skip non-selected location levels + if (["country", "state", "city", "areaId"].includes(key)) { + if (key !== locationPriority) return; + } + + if (["areaId", "min_price", "max_price"].includes(key)) + value = Number(value); + if (key === "category") params.append("category_slug", value); + else if (key === "query") params.append("search", value); + else if (key === "date_posted") params.append("posted_since", value); + else params.append(key, value); + }); + + return params.toString(); +}; + +const buildCanonicalParams = (searchParams) => { + const params = new URLSearchParams(); + + const { category, query, lang } = searchParams || {}; + + if (category) params.append("category", category); + if (query) params.append("search", query); + // Add lang to canonical params for consistency with sitemap + if (lang) params.append("lang", lang); + + return params.toString(); +}; + +export const generateMetadata = async ({ searchParams }) => { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + + try { + const originalSearchParams = await searchParams; + const langCode = originalSearchParams?.lang || "en"; + const slug = originalSearchParams?.category || ""; // change to your param name if needed + + let title = process.env.NEXT_PUBLIC_META_TITLE; + let description = process.env.NEXT_PUBLIC_META_DESCRIPTION; + let keywords = process.env.NEXT_PUBLIC_META_kEYWORDS; + let image = ""; + + if (slug) { + // Fetch category-specific SEO + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-categories?slug=${slug}`, + { + headers: { "Content-Language": langCode || "en" }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + } + ); + + const data = await response.json(); + const selfCategory = data?.self_category; + + title = selfCategory?.translated_name || title; + description = selfCategory?.translated_description || description; + keywords = + generateKeywords(selfCategory?.translated_description) || keywords; + image = selfCategory?.image || image; + } else { + // Fetch default ad listing SEO + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=ad-listing`, + { + headers: { "Content-Language": langCode || "en" }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + } + ); + const data = await res.json(); + const adListing = data?.data?.[0]; + + title = adListing?.translated_title || title; + description = adListing?.translated_description || description; + keywords = adListing?.translated_keywords || keywords; + image = adListing?.image || image; + } + + const baseUrl = process.env.NEXT_PUBLIC_WEB_URL; + const paramsStr = buildCanonicalParams(originalSearchParams); + const canonicalUrl = `${baseUrl}/ads${paramsStr ? `?${paramsStr}` : ""}`; + + return { + title, + description, + openGraph: { + images: image ? [image] : [], + }, + keywords, + alternates: { + canonical: canonicalUrl, + }, + }; + } catch (error) { + console.error("Error fetching MetaData:", error); + return null; + } +}; + +const getAllItems = async (langCode, searchParams) => { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + + try { + const queryString = buildIndexableParams(searchParams) + ? buildIndexableParams(searchParams) + : ""; + const url = `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT + }get-item?page=1${queryString ? `&${queryString}` : ""}`; + + const res = await fetch(url, { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + }); + + const data = await res.json(); + return data?.data?.data || []; + } catch (error) { + console.error("Error fetching Product Items Data:", error); + return []; + } +}; + +const AdsPage = async ({ searchParams }) => { + const originalSearchParams = await searchParams; + const langCode = originalSearchParams?.lang || "en"; + const AllItems = await getAllItems(langCode, originalSearchParams); + + const jsonLd = AllItems + ? { + "@context": "https://schema.org", + "@type": "ItemList", + itemListElement: AllItems.map((product, index) => ({ + "@type": "ListItem", + position: index + 1, // Position starts at 1 + item: { + "@type": "Product", + productID: product?.id, + name: product?.translated_item?.name || "", + description: product?.translated_item?.description || "", + image: product?.image || "", + url: `${process.env.NEXT_PUBLIC_WEB_URL}/ad-details/${product?.slug}`, + category: { + "@type": "Thing", + name: product?.category?.translated_name || "", + }, + offers: { + "@type": "Offer", + price: product.price || undefined, + priceCurrency: product?.price ? "USD" : undefined, + availability: product?.price + ? "https://schema.org/InStock" + : "https://schema.org/PreOrder", + }, + countryOfOrigin: product?.translated_item?.country || "", + }, + })), + } + : null; + + return ( + <> + + + + ); +}; +export default AdsPage; diff --git a/app/blogs/[slug]/page.jsx b/app/blogs/[slug]/page.jsx new file mode 100644 index 0000000..5e4a0ed --- /dev/null +++ b/app/blogs/[slug]/page.jsx @@ -0,0 +1,119 @@ +import StructuredData from "@/components/Layout/StructuredData"; +import BlogDetailPage from "@/components/PagesComponent/BlogDetail/BlogDetailPage"; +import { SEO_REVALIDATE_SECONDS } from "@/lib/constants"; + +const stripHtml = (html) => { + return html.replace(/<[^>]*>/g, ""); // Regular expression to remove HTML tags +}; + +// Function to format the date correctly (ISO 8601) +const formatDate = (dateString) => { + // Remove microseconds and ensure it follows ISO 8601 format + const validDateString = dateString.slice(0, 19) + "Z"; // Remove microseconds and add 'Z' for UTC + return validDateString; +}; + +export const generateMetadata = async ({ params, searchParams }) => { + try { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + const slugParams = await params; + const langParams = await searchParams; + const langCode = langParams?.lang || "en"; + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}blogs?slug=${slugParams?.slug}`, + { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + } + ); + + if (!response.ok) { + throw new Error("Failed to fetch metadata"); + } + + const responseData = await response.json(); + const data = responseData?.data?.data[0]; + + const plainTextDescription = data?.translated_description?.replace( + /<\/?[^>]+(>|$)/g, + "" + ); + + return { + title: data?.translated_title || process.env.NEXT_PUBLIC_META_TITLE, + description: plainTextDescription + ? plainTextDescription + : process.env.NEXT_PUBLIC_META_DESCRIPTION, + openGraph: { + images: data?.image ? [data?.image] : [], + }, + keywords: data?.translated_tags || process.env.NEXT_PUBLIC_META_kEYWORDS, + }; + } catch (error) { + console.error("Error fetching MetaData:", error); + return null; + } +}; + +const fetchSingleBlogItem = async (slug, langCode) => { + try { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + const url = `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}blogs?slug=${slug}`; + const response = await fetch(url, { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + }); + + if (!response.ok) { + throw new Error("Failed to fetch blog data"); + } + + const responseData = await response.json(); + return responseData?.data?.data[0] || []; + } catch (error) { + console.error("Error fetching Blog Items Data:", error); + return []; + } +}; + +const BlogPage = async ({ params, searchParams }) => { + const { slug } = await params; + const langCode = (await searchParams).lang || "en"; + const singleBlog = await fetchSingleBlogItem(slug, langCode); + + const jsonLd = singleBlog + ? { + "@context": "https://schema.org", + "@type": "BlogPosting", + headline: singleBlog?.translated_title, + description: singleBlog?.translated_description + ? stripHtml(singleBlog.translated_description) + : "No description available", // Strip HTML from description + url: `${process.env.NEXT_PUBLIC_WEB_URL}/blogs/${singleBlog?.slug}`, + image: singleBlog?.image, + datePublished: singleBlog?.created_at + ? formatDate(singleBlog.created_at) + : "", // Format date to ISO 8601 + keywords: singleBlog?.translated_tags + ? singleBlog.translated_tags.join(", ") + : "", // Adding tags as keywords + } + : null; + + return ( + <> + + + + ); +}; + +export default BlogPage; diff --git a/app/blogs/page.jsx b/app/blogs/page.jsx new file mode 100644 index 0000000..7f582f3 --- /dev/null +++ b/app/blogs/page.jsx @@ -0,0 +1,123 @@ +import StructuredData from "@/components/Layout/StructuredData"; +import Blogs from "@/components/PagesComponent/Blogs/Blogs"; +import { SEO_REVALIDATE_SECONDS } from "@/lib/constants"; + +export const dynamic = "force-dynamic"; + +export const generateMetadata = async ({ searchParams }) => { + try { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + const params = await searchParams; + const langCode = params?.lang || "en"; + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=blogs`, + { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + } + ); + + if (!response.ok) { + throw new Error("Failed to fetch blogs metadata"); + } + const data = await response.json(); + const blogs = data?.data[0]; + return { + title: blogs?.translated_title || process.env.NEXT_PUBLIC_META_TITLE, + description: + blogs?.translated_description || + process.env.NEXT_PUBLIC_META_DESCRIPTION, + openGraph: { + images: blogs?.image ? [blogs?.image] : [], + }, + keywords: + blogs?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS, + }; + } catch (error) { + console.error("Error fetching MetaData:", error); + return null; + } +}; + +const stripHtml = (html) => { + return html.replace(/<[^>]*>/g, ""); // Regular expression to remove HTML tags +}; + +// Function to format the date correctly (ISO 8601) +const formatDate = (dateString) => { + // Remove microseconds and ensure it follows ISO 8601 format + const validDateString = dateString.slice(0, 19) + "Z"; // Remove microseconds and add 'Z' for UTC + return validDateString; +}; + +const fetchBlogItems = async (langCode, tag) => { + try { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + let url = `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}blogs`; + + if (tag) { + url += `?tag=${encodeURIComponent(tag)}`; + } + + const response = await fetch(url, { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + }); + + if (!response.ok) { + throw new Error("Failed to fetch blogs json-ld data"); + } + const data = await response.json(); + return data?.data?.data || []; + } catch (error) { + console.error("Error fetching Blog Items Data:", error); + return []; + } +}; + +const BlogsPage = async ({ searchParams }) => { + const params = await searchParams; + const langCode = params?.lang || "en"; + const tag = params?.tag || null; + const blogItems = await fetchBlogItems(langCode, tag); + + const jsonLd = blogItems + ? { + "@context": "https://schema.org", + "@type": "ItemList", + itemListElement: blogItems.map((blog, index) => ({ + "@type": "ListItem", + position: index + 1, + item: { + "@type": "BlogPosting", + headline: blog?.translated_title, + description: blog?.translated_description + ? stripHtml(blog.translated_description) + : "No description available", // Strip HTML from description + url: `${process.env.NEXT_PUBLIC_WEB_URL}/blogs/${blog?.slug}`, + image: blog?.image, + datePublished: blog?.created_at ? formatDate(blog.created_at) : "", // Format date to ISO 8601 + keywords: blog?.translated_tags + ? blog.translated_tags.join(", ") + : "", // Adding tags as keywords + }, + })), + } + : null; + return ( + <> + + + + ); +}; + +export default BlogsPage; diff --git a/app/chat/page.jsx b/app/chat/page.jsx new file mode 100644 index 0000000..79fdca2 --- /dev/null +++ b/app/chat/page.jsx @@ -0,0 +1,7 @@ +import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard"; + +const ChatPage = () => { + return ; +}; + +export default ChatPage; diff --git a/app/contact-us/page.jsx b/app/contact-us/page.jsx new file mode 100644 index 0000000..53600f3 --- /dev/null +++ b/app/contact-us/page.jsx @@ -0,0 +1,46 @@ +import ContactUs from "@/components/PagesComponent/Contact/ContactUs"; +import { SEO_REVALIDATE_SECONDS } from "@/lib/constants"; + +export const dynamic = "force-dynamic"; + + +export const generateMetadata = async ({ searchParams }) => { + try { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + const params = await searchParams; + const langCode = params?.lang || "en"; + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=contact-us`, + { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + } + ); + const data = await res.json(); + const contactUs = data?.data?.[0]; + return { + title: contactUs?.translated_title || process.env.NEXT_PUBLIC_META_TITLE, + description: + contactUs?.translated_description || + process.env.NEXT_PUBLIC_META_DESCRIPTION, + openGraph: { + images: contactUs?.image ? [contactUs?.image] : [], + }, + keywords: + contactUs?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS, + }; + } catch (error) { + console.error("Error fetching MetaData:", error); + return null; + } +}; + +const ContactUsPage = () => { + return ; +}; + +export default ContactUsPage; diff --git a/app/edit-listing/[id]/page.jsx b/app/edit-listing/[id]/page.jsx new file mode 100644 index 0000000..f52c8a4 --- /dev/null +++ b/app/edit-listing/[id]/page.jsx @@ -0,0 +1,9 @@ +import EditListing from "@/components/PagesComponent/EditListing/EditListing"; + +const EditListingPage = async (props) => { + const params = await props.params; + const id = await params.id; + return ; +}; + +export default EditListingPage; diff --git a/app/error.jsx b/app/error.jsx new file mode 100644 index 0000000..166e4eb --- /dev/null +++ b/app/error.jsx @@ -0,0 +1,37 @@ +"use client"; // Error components must be Client Components +import { useEffect } from "react"; +import somthingWrong from "../public/assets/something_went_wrong.svg"; +import { t } from "@/utils"; +import { Button } from "@/components/ui/button"; +import CustomImage from "@/components/Common/CustomImage"; +import { useNavigate } from "@/components/Common/useNavigate"; + +export default function Error({ error }) { + const { navigate } = useNavigate(); + useEffect(() => { + // Log the error to an error reporting service + console.error(error); + }, [error]); + const navigateHome = () => { + navigate("/"); + }; + return ( +
+ +

+ {t("somthingWentWrong")} +

+
+ {t("tryLater")} + +
+
+ ); +} diff --git a/app/faqs/page.jsx b/app/faqs/page.jsx new file mode 100644 index 0000000..8b8ae60 --- /dev/null +++ b/app/faqs/page.jsx @@ -0,0 +1,45 @@ +import FaqsPage from "@/components/PagesComponent/Faq/FaqsPage"; +import { SEO_REVALIDATE_SECONDS } from "@/lib/constants"; + +export const dynamic = "force-dynamic"; + +export const generateMetadata = async ({ searchParams }) => { + try { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + const params = await searchParams; + const langCode = params?.lang || "en"; + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=faqs`, + { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + } + ); + const data = await response.json(); + const faqs = data?.data?.[0]; + return { + title: faqs?.translated_title || process.env.NEXT_PUBLIC_META_TITLE, + description: + faqs?.translated_description || + process.env.NEXT_PUBLIC_META_DESCRIPTION, + openGraph: { + images: faqs?.image ? [faqs?.image] : [], + }, + keywords: + faqs?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS, + }; + } catch (error) { + console.error("Error fetching MetaData:", error); + return null; + } +}; + +const page = () => { + return ; +}; + +export default page; diff --git a/app/favorites/page.jsx b/app/favorites/page.jsx new file mode 100644 index 0000000..b57c863 --- /dev/null +++ b/app/favorites/page.jsx @@ -0,0 +1,9 @@ +import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard" + +export default function FavoritesPage() { + return ( + <> + + + ) +} \ No newline at end of file diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..2626168 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,274 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; +} + +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + } +} + +@layer utilities { + .text-balance { + text-wrap: balance; + } +} + +@layer base { + :root { + --background: #ffffff; + --foreground: 0 0% 3.9%; + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + --primary: #00b2ca; + --primary-foreground: 0 0% 98%; + --secondary: 0 0% 96.1%; + --secondary-foreground: 0 0% 9%; + --muted: #f6f5fa; + --muted-foreground: 0 0% 45.1%; + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + --destructive: #dc3545; + --destructive-foreground: 0 0% 98%; + --border: #d3d3d3; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem; + } + + .dark { + --background: 0 0% 3.9%; + --foreground: 0 0% 98%; + --card: 0 0% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: #00b2ca; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + --font-color: #ffffff; + --light-font-color: #595b6c; + } +} + +@layer base { + * { + @apply border-border; + } + + body { + @apply bg-[background] text-foreground; + } +} + +@layer utilities { + + + .landingSecHeader { + @apply text-center text-4xl lg:text-5xl font-light; + } + + .outlinedSecHead { + @apply p-3 px-4 border border-primary text-primary rounded-md font-semibold text-center; + } + + .storeIcons { + @apply max-w-max w-full sm:w-[170px] md:w-[215px] lg:w-[235px] h-auto; + } + + .footerSocialLinks { + @apply flex items-center justify-center w-[40px] h-[40px] rounded-md p-2 transition-all duration-500 bg-white/15; + } + + .footerContactIcons { + @apply flex items-center justify-center min-w-[48px] w-[48px] h-[48px] rounded-md p-[10px] transition-all duration-500 bg-white/15; + } + + + .footerSocialLinks:hover, + .footerContactIcons:hover { + background-color: var(--primary-color); + box-shadow: 0px 8px 28px 0px var(--primary-color); + } + + .footerLabel { + @apply text-white opacity-65 text-sm transition-colors; + } + + .footerLabel:hover { + color: var(--primary-color); + } + + .space-between { + @apply flex items-center justify-between; + } + + .labelInputCont { + @apply flex flex-col gap-2; + } + + .requiredInputLabel { + @apply after:content-['*'] after:text-destructive; + } + + .loader-container-otp { + @apply flex items-center justify-center h-7 py-1 px-2; + } + + .loader-otp { + @apply border-4 border-t-[var(--primary-color)] border-[#f3f3f3] rounded-full w-5 h-5 animate-spin; + } + + .profileActiveTab { + @apply py-2 px-4 bg-primary rounded-full text-white w-max + } + + .sectionTitle { + @apply text-xl sm:text-2xl font-medium capitalize + } + + .loader { + @apply w-full h-full relative flex items-center justify-center m-auto + } + + .text_ellipsis { + @apply overflow-hidden text-ellipsis whitespace-nowrap + } + + .scrollbar-none::-webkit-scrollbar { + display: none; + } + + /* Hide scrollbar for IE, Edge, and Firefox */ + .scrollbar-none { + -ms-overflow-style: none; + /* IE and Edge */ + scrollbar-width: none; + /* Firefox */ + } +} + +/* .place_search div { + width: 100%; +} */ + +.formWrapper .react-tel-input .special-label { + display: none !important; +} + +.react-tel-input .form-control { + width: 100% !important; + height: 40px !important; + border: 1px solid lightgray !important; + outline: none !important; + border-radius: 4px !important; +} + +.react-tel-input .flag-dropdown { + background-color: transparent !important; +} + +/* Update focus styles to match shadcn Input */ +.react-tel-input .form-control:focus, +.react-tel-input .form-control:focus-visible { + outline: none !important; + box-shadow: 0 0 0 2px var(--background), 0 0 0 4px var(--primary) !important; + border-color: transparent !important; +} + + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + margin: 0; +} + + +::-webkit-scrollbar { + width: 5px !important; + width: 5px !important; +} + +/* Track */ +::-webkit-scrollbar-track { + border-radius: 10px !important; + background-color: lightgray; + border-radius: 10px !important; + background-color: lightgray; +} + +/* Handle */ +::-webkit-scrollbar-thumb { + background: var(--primary) !important; + border-radius: 10px !important; + background: var(--primary) !important; + border-radius: 10px !important; +} + + +/* RTL overrides for react-phone-input-2*/ +[dir='rtl'] .react-tel-input .form-control { + padding-left: inherit; + padding-right: 48px; +} + +[dir='rtl'] .react-tel-input .selected-flag { + padding: 0 8px 0 0; +} + +[dir='rtl'] .react-tel-input .selected-flag .arrow { + left: auto; + right: 20px; +} + +[dir=rtl] input[type=tel i] { + direction: rtl; +} + +.perspective-1000 { + perspective: 1000px; +} + +.transform-style-preserve-3d { + transform-style: preserve-3d; +} + +.backface-hidden { + backface-visibility: hidden; +} + +.rotate-y-180 { + transform: rotateY(180deg); +} \ No newline at end of file diff --git a/app/job-applications/page.jsx b/app/job-applications/page.jsx new file mode 100644 index 0000000..c2fd759 --- /dev/null +++ b/app/job-applications/page.jsx @@ -0,0 +1,7 @@ +import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard"; + +const JobApplicationsPage = () => { + return ; +}; + +export default JobApplicationsPage; diff --git a/app/landing/page.jsx b/app/landing/page.jsx new file mode 100644 index 0000000..63f60ad --- /dev/null +++ b/app/landing/page.jsx @@ -0,0 +1,57 @@ +import Layout from "@/components/Layout/Layout"; +import AnythingYouWant from "@/components/PagesComponent/LandingPage/AnythingYouWant"; +import OurBlogs from "@/components/PagesComponent/LandingPage/OurBlogs"; +import QuickAnswers from "@/components/PagesComponent/LandingPage/QuickAnswers"; +import WorkProcess from "@/components/PagesComponent/LandingPage/WorkProcess"; +import { SEO_REVALIDATE_SECONDS } from "@/lib/constants"; + +export const dynamic = "force-dynamic"; + +export const generateMetadata = async ({ searchParams }) => { + try { + if (process.env.NEXT_PUBLIC_SEO === "false") return; + const params = await searchParams; + const langCode = params?.lang || "en"; + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=landing`, + { + headers: { + "Content-Language": langCode || "en", + }, + next: { + revalidate: SEO_REVALIDATE_SECONDS, + }, + } + ); + const data = await res.json(); + const landing = data?.data?.[0]; + + return { + title: landing?.translated_title || process.env.NEXT_PUBLIC_META_TITLE, + description: + landing?.translated_description || + process.env.NEXT_PUBLIC_META_DESCRIPTION, + openGraph: { + images: landing?.image ? [landing?.image] : [], + }, + keywords: + landing?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS, + }; + } catch (error) { + console.error("Error fetching MetaData:", error); + return null; + } +}; + +const LandingPage = () => { + return ( + + + + + + + ); +}; + +export default LandingPage; diff --git a/app/layout.js b/app/layout.js new file mode 100644 index 0000000..8d83ea7 --- /dev/null +++ b/app/layout.js @@ -0,0 +1,46 @@ +import { Manrope } from "next/font/google"; +import "./globals.css"; +import { Providers } from "@/redux/store/providers"; +import { Toaster } from "@/components/ui/sonner"; +// import Script from "next/script"; + +const manrope = Manrope({ + weight: ["200", "300", "400", "500", "600", "700", "800"], + subsets: ["latin"], + display: "swap", +}); + +export const generateMetadata = () => { + return { + title: process.env.NEXT_PUBLIC_META_TITLE, + description: process.env.NEXT_PUBLIC_META_DESCRIPTION, + keywords: process.env.NEXT_PUBLIC_META_kEYWORDS, + openGraph: { + title: process.env.NEXT_PUBLIC_META_TITLE, + description: process.env.NEXT_PUBLIC_META_DESCRIPTION, + keywords: process.env.NEXT_PUBLIC_META_kEYWORDS, + }, + }; +}; + +export default function RootLayout({ children }) { + return ( + + + {/*