Commit e4cb6e02 by jaymehta

enquire now

1 parent 7fe6a04a
import Image from "next/image";
import React, { Fragment, useState } from "react";
import React, { Fragment, useEffect, useState } from "react";
import { Button } from "react-bootstrap";
import { fadeIn, zoomIn, slideFromLeft, slideFromRight } from "../animationvariants.js";
import { motion } from "framer-motion";
import { getSession } from "next-auth/react";
import { DatePicker } from "antd";
import { date } from "yup";
import { sendEnquiry } from "../../redux/actions/enquiryAction.js";
import { useDispatch, useSelector } from "react-redux";
import { toast } from "react-toastify";
import { getCurrentEndUser } from "../../redux/actions/userActions.js";
const DetailInfo = ({ activityById }) => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(getCurrentEndUser());
}, []);
// const [session, setSession] = useState(null);
const [enqDate, setenqDate] = useState();
const { loadedUser } = useSelector(state => state.loadedUser);
const { endUser } = useSelector(state => state.endUser);
// useEffect(() => {
// const fetchSession = async () => {
// setSession(await getSession());
// };
// fetchSession();
// // dispatch(getLoggedInVendor());
// }, []);
const [showInfo, setShowInfo] = useState(false);
const [isToggled, setIsToggled] = useState(false);
console.log("session", endUser);
const handleClick = () => {
setIsToggled(!isToggled);
};
......@@ -79,16 +102,24 @@ const DetailInfo = ({ activityById }) => {
<div className="price">
${activityById.data.attributes.pricePerPerson} {activityById.data.attributes.offers && <span>{activityById.data.attributes.offers}% Off</span>}
</div>
<div className="mb-4">
{activityById.data.attributes.description}
</div>
<div className="mb-4">{activityById.data.attributes.description}</div>
<div className="location">
Location & Address <span>{activityById.data.attributes.activityType}</span>
</div>
<div className="mb-2">Chelsea </div>
<div className="">{activityById.data.attributes.address}</div>
<div className="btn-row">
<Button variant="primary me-3">Book Now</Button>
<Button
onClick={async () => {
console.log("hello");
let res = await sendEnquiry({ activityId: activityById.data.id, userId: endUser.id, vendorId: activityById.data.attributes.vendor.data.id });
console.log("res", res);
toast.success("Enquiry sent successfully, our team will get back to you shortly! Thank you!");
}}
variant="primary me-3"
>
Enquire Now
</Button>
<Button variant="secondary">
Gift Now{" "}
<span className="image-container btn-gift">
......@@ -106,7 +137,7 @@ const DetailInfo = ({ activityById }) => {
<span className="image-container">
<Image layout="fill" alt="" className="image img-fluid" src="/images/availability/month.svg" />
</span>
From: {activityById.data.attributes.fromDate} To: {activityById.data.attributes.toDate}
From: {activityById.data.attributes.fromDate} To: {activityById.data.attributes.toDate}
</li>
<li>
<span className="image-container">
......
......@@ -13,7 +13,7 @@ import "swiper/css/pagination";
import "swiper/css/navigation";
const LetDiscover = () => {
const [activeIndex, setActiveIndex] = useState(null);
const handleTitleClick = (index) => {
const handleTitleClick = index => {
// Check if the clicked index is already active
if (activeIndex === index) {
return; // Do nothing if it's already active
......@@ -21,7 +21,7 @@ const LetDiscover = () => {
// Toggle the active index if it's different from the clicked index
setActiveIndex(index);
};
const letDiscoverData = [
{
image: "/images/discover/01.png",
......@@ -150,8 +150,7 @@ const LetDiscover = () => {
return (
<SwiperSlide>
<motion.div variants={zoomIn("left", 0.3)} initial={"hidden"} whileInView={"show"} viewport={{ once: false, amount: 0.2 }}>
<a className={isActive ? "active" : ""}
onClick={() => handleTitleClick(index)}>
<a className={isActive ? "active" : ""} onClick={() => handleTitleClick(index)}>
<span className="image-container">
<Image layout="fill" alt="" className="image img-fluid" src={data.image} />
</span>
......
......@@ -332,21 +332,21 @@ const ListingFilter = () => {
<div className="head">Date</div>
</div>
<div className="inner">
<div className="row">
<div className="col-6">
<div>From</div>
<Space direction="vertical">
<DatePicker onChange={onChange} />
</Space>
</div>
<div className="col-6">
<div>To</div>
<Space direction="vertical">
<DatePicker onChange={onChange} />
</Space>
<div className="row">
<div className="col-6">
<div>From</div>
<Space direction="vertical">
<DatePicker onChange={onChange} />
</Space>
</div>
<div className="col-6">
<div>To</div>
<Space direction="vertical">
<DatePicker onChange={onChange} />
</Space>
</div>
</div>
</div>
</div>
</div>
<div className="box-01">
<div className="p-all">
......
import Image from "next/image";
import { useRouter } from "next/router";
import React from "react";
import { Button } from "react-bootstrap";
import { cleanImage } from "../../services/imageHandling";
const ListingItems = ({allActivitiesData}) => {
console.log("allActivitiesData",allActivitiesData )
const ListingItems = ({ allActivitiesData }) => {
console.log("allActivitiesData", allActivitiesData);
const router = useRouter();
return (
<>
<div className="listing-items">
<div className="row">
{allActivitiesData.data &&
{allActivitiesData &&
allActivitiesData.data.map(data => {
return (
<div className="col-md-3">
<div className="item">
<div className="browse-experiences-item">
<div className="img-wrapper">
<div className="browse-experiences-item">
<div className="img-wrapper">
<span className="image-container">
<Image layout="fill" alt="" className="image img-fluid" src={cleanImage(data.attributes?.image?.data?.attributes)} />
</span>
<div className="top-rated">Top Rated</div>
</div>
<div className="info">
<div className="top-name">
<div className="title">{data?.attributes?.name}</div>
<div className="rating-wishlist">
<div className="rating">
{data?.attributes?.rating}
<span className="image-container">
<Image layout="fill" alt="" className="image img-fluid" src={cleanImage(data.attributes?.image?.data?.attributes)} />
<Image layout="fill" alt="" className="image img-fluid" src="/images/icons/star.svg" />
</span>
<div className="top-rated">Top Rated</div>
</div>
<div className="info">
<div className="top-name">
<div className="title">{data?.attributes?.name}</div>
<div className="rating-wishlist">
<div className="rating">
{data?.attributes?.rating}
<span className="image-container">
<Image layout="fill" alt="" className="image img-fluid" src="/images/icons/star.svg" />
</span>
</div>
<div className="wishlist">
<span className="image-container">
<Image layout="fill" alt="" className="image img-fluid" src="/images/icons/wishlist.svg" />
</span>
</div>
</div>
</div>
<div className="discription">
{data.discription} <a href="">Read More</a>
</div>
<div className="price">
${data?.attributes?.pricePerPerson} <span className="off">{data?.attributes?.off}% OFF</span>
</div>
<div className="detail">
<div className="">For 1 Night</div>
<div className="">Includes taxes & Fees</div>
</div>
<div className="explore-now">
<Button href="/listing" variant="primary">Explore Now</Button>
</div>
<div className="wishlist">
<span className="image-container">
<Image layout="fill" alt="" className="image img-fluid" src="/images/icons/wishlist.svg" />
</span>
</div>
</div>
</div>
<div className="discription">
{data.discription} <a href="">Read More</a>
</div>
<div className="price">
${data?.attributes?.pricePerPerson} <span className="off">{data?.attributes?.off}% OFF</span>
</div>
<div className="detail">
<div className="">For 1 Night</div>
<div className="">Includes taxes & Fees</div>
</div>
<div className="explore-now">
<Button
onClick={() => {
router.push(`/activities/${data.id}`);
}}
variant="primary"
>
Explore Now
</Button>
</div>
</div>
</div>
</div>
</div>
);
......
......@@ -49,7 +49,12 @@ const Login = props => {
}
if (signInResponse.ok) {
setLoading(false);
router.push("/vendor/business-details");
if (props.type != "user") {
router.push("/vendor/business-details");
}
if (props.type == "user") {
router.push("/listing");
}
}
// router.push("")
}}
......
......@@ -17,7 +17,7 @@ import { signIn } from "next-auth/react";
import { Loader } from "react-bootstrap-typeahead";
const Signup = props => {
console.log(props.type);
console.log("props.type", props.type);
const [otp, setOtp] = useState(new Array(4).fill(""));
const [isOtpSent, setOtpSent] = useState(false);
const [otpVerified, setOtpVerified] = useState(false);
......@@ -117,7 +117,13 @@ const Signup = props => {
setLoading(true);
e.preventDefault();
console.log("values", values);
const user = await dispatch(registerUser({ ...values, role: "vendor" }));
let user;
if (props.type == "vendor") {
user = await dispatch(registerUser({ ...values, role: "vendor" }));
}
if (props.type == "user") {
user = await dispatch(registerUser({ ...values, role: "endUser" }));
}
console.log("response", user);
if (user?.data?.status == "fail") {
toast.error(user?.data.message);
......@@ -140,7 +146,12 @@ const Signup = props => {
});
setLoading(false);
console.log("result", result);
router.push("/vendor/business-details");
if (props.type == "vendor") {
router.push("/vendor/business-details");
}
if (props.type == "user") {
router.push("/signup/user/thankyou");
}
// toast.success("User registered successflly");
} else if (!otpRes.data.ok) {
setLoading(false);
......
......@@ -2,39 +2,41 @@ import Image from "next/image";
import React, { Fragment } from "react";
import { renderImage } from "../../services/imageHandling";
import { Button } from "react-bootstrap";
import { useRouter } from "next/router";
const ThankYou = () => {
return (
<Fragment>
<div className="contaier-fluid login-banner-image">
<div className="row">
<div className="col-12 col-lg-4 login-div">
<div className="thankyou-div">
<span className="image-container">
<Image src={renderImage("/images/login/success.png")} layout="fill" className="image" />
</span>
<h2 className="mt-2 px-4 mb-0">Thank you for Signing Up with Us</h2>
<p className="mb-4">Your Profile is been created successfully</p>
</div>
const router = useRouter();
return (
<Fragment>
<div className="contaier-fluid login-banner-image">
<div className="row">
<div className="col-12 col-lg-4 login-div">
<div className="thankyou-div">
<span className="image-container">
<Image src={renderImage("/images/login/success.png")} layout="fill" className="image" />
</span>
<h2 className="mt-2 px-4 mb-0">Thank you for Signing Up with Us</h2>
<p className="mb-4">Your Profile is been created successfully</p>
</div>
<div className="form-container">
<div className="input-group mb-2">
<Button
type="button"
className="btn btn-primary btn-submit"
// onClick={() => {
// router.push("/")
// }}
>
Proceed to Dashboard
</Button>
</div>
</div>
</div>
</div>
<div className="form-container">
<div className="input-group mb-2">
<Button
type="button"
className="btn btn-primary btn-submit"
onClick={() => {
router.push("/");
}}
>
Proceed to Home Page
</Button>
</div>
</div>
</Fragment>
);
</div>
</div>
</div>
</Fragment>
);
};
export default ThankYou;
\ No newline at end of file
export default ThankYou;
import Layout from "../components/layout/Layout";
import Listing from "../components/listing/Listing";
import { getActivitiesByVendor } from "../redux/actions/activityAction";
import { getActivitiesByFilters } from "../redux/actions/activityAction";
import { wrapper } from "../redux/store";
export default function ListingPage() {
......@@ -23,7 +23,7 @@ export default function ListingPage() {
/** For server side rendering */
export const getServerSideProps = wrapper.getServerSideProps(store => async ({ req, query }) => {
try {
await store.dispatch(getActivitiesByVendor())
await store.dispatch(getActivitiesByFilters({}))
return {
props: {},
......
import axios from "axios";
import { CLEAR_ERRORS, ENQUIRY_SUBMIT_FAIL, ENQUIRY_SUBMIT_REQUEST, ENQUIRY_SUBMIT_SUCCESS } from "../constants/enquiryConstants";
export const postEnqiryDetails = enquiryData => async dispatch => {
try {
dispatch({
type: ENQUIRY_SUBMIT_REQUEST
});
export const sendEnquiry = async ({ activityId, userId, date, vendorId }) => {
const data = {
data: {
experience: activityId,
endUser: userId,
vendor: vendorId,
date,
status: "pending"
}
};
const config = {
headers: {
"Content-Type": "application/json"
}
};
console.log("data", data);
const response = await axios.post(`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/enquires`, data, config);
const config = {
headers: {
"Content-Type": "application/json"
}
};
const response = await axios.post(
`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/leads`,
{
data: {
fullName: enquiryData.fullName,
mobileNumber: enquiryData.mobileNumber,
email: enquiryData.email,
projects: enquiryData.projects,
comments: enquiryData.comments
}
},
config
);
dispatch({
type: ENQUIRY_SUBMIT_SUCCESS,
payload: response.data
});
} catch (error) {
console.log("Error while submitting enquiry details: ");
console.log(error);
dispatch({
type: ENQUIRY_SUBMIT_FAIL,
payload: error.response.data
});
}
return response.data;
};
// Clear errors
......
......@@ -14,10 +14,14 @@ import {
REGISTER_USER_REQUEST,
REGISTER_USER_SUCCESS,
REGISTER_USER_FAIL,
CLEAR_ERRORS
CLEAR_ERRORS,
GET_END_USER_REQUEST,
GET_END_USER_SUCCESS,
GET_END_USER_FAIL
} from "../constants/userConstants";
import axios from "axios";
import { getSession } from "next-auth/react";
import qs from "qs";
// register a new user.
export const registerUser = userData => async dispatch => {
......@@ -52,9 +56,10 @@ export const registerUser = userData => async dispatch => {
// Immediately after user creation based on the role of the user we need to create entry into the corresponding extension table.
// Do for End user
if (userData.role === "Channel Partner") {
userData["userId"] = response.data.user.id;
await registerChannelPartner(userData);
if (userData.role === "endUser") {
console.log("userdata", userData);
// userData["userId"] = response.data.user.id;
await registerEndUser({ ...userData, userId: response.data.user.id });
}
if (userData.role === "vendor") {
console.log("userdata", userData);
......@@ -103,6 +108,32 @@ const registerVendor = async vendorData => {
return response;
};
const registerEndUser = async vendorData => {
const authUser = await axios.post(`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/auth/local`, {
identifier: vendorData.email,
password: vendorData.password
});
console.log("jwt", authUser);
const config = {
headers: {
Authorization: `Bearer ${authUser.data.jwt}`,
"Content-Type": "application/json"
}
};
const data = {
data: {
mobileNo: vendorData.mobile,
name: vendorData.fullname,
email: vendorData.email,
user: authUser.data.user.id
}
};
const response = await axios.post(`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/end-users`, data, config);
return response;
};
// register a new user.
export const loadUser = () => async dispatch => {
const session = await getSession();
......@@ -278,97 +309,6 @@ export const clearErrors = () => async dispatch => {
});
};
/** Channel partner record to be created alongwith user creation. */
/** This is an internal utility method which creates a CP when a user is created. */
const registerChannelPartner = async channelPartnerData => {
const {
data: { user, jwt }
} = await axios.post(`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/auth/local`, {
identifier: channelPartnerData.email,
password: channelPartnerData.password
});
// First save the main cp record.
const config = {
headers: {
Authorization: `Bearer ${jwt}`,
"Content-Type": "application/json"
}
};
const cpData = {
data: {
companyName: channelPartnerData.companyName,
companyType: channelPartnerData.companyType,
contactPersonName: channelPartnerData.contactPersonName,
email: channelPartnerData.email,
communicationAddress: channelPartnerData.communicationAddress,
mobileNo: channelPartnerData.mobileNo,
city: channelPartnerData.city,
state: channelPartnerData.state,
reraNumber: channelPartnerData.reraNumber,
regionOfOperation: channelPartnerData.regionOfOperation,
sourcingManager: channelPartnerData.sourcingManager,
pan: channelPartnerData.pan,
memberOf: channelPartnerData.memberOf,
termsAndConditions: channelPartnerData.termsAndConditions,
/** userId is added after user is created in the registerUser method. */
user: channelPartnerData.userId,
publishedAt: null
}
};
const response = await axios.post(`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/channel-partners`, cpData, config);
// Immediately after cp creation we can now go ahead and login with this user to generate a token, and use that to upload the image.
if (channelPartnerData.panFile && channelPartnerData.panFile.length !== 0) {
const panFileFormData = new FormData();
panFileFormData.append("field", "panFile");
panFileFormData.append("ref", "api::channel-partner.channel-partner");
panFileFormData.append("refId", response.data.data.id);
panFileFormData.append("files", channelPartnerData.panFile[0]);
await axios.post(`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/upload`, panFileFormData, {
headers: {
Authorization: `Bearer ${jwt}`,
"Content-Type": "multipart/form-data"
}
});
}
};
/** End user record to be created alongwith user creation. */
/** This is an internal utility method which creates a end user when a user is created. */
const registerEndUser = async euData => {
const {
data: { user, jwt }
} = await axios.post(`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/auth/local`, {
identifier: euData.email,
password: euData.password
});
// First save the main cp record.
const config = {
headers: {
Authorization: `Bearer ${jwt}`,
"Content-Type": "application/json"
}
};
const endUserData = {
data: {
mobileNo: euData.mobileNo,
fullName: euData.fullName,
whatsappAccepted: euData.whatsappAccepted,
email: euData.email,
/** userId is added after user is created in the registerUser method. */
user: euData.userId,
publishedAt: null
}
};
const response = await axios.post(`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/end-users`, endUserData, config);
};
/** End user record to be created alongwith user creation. */
/** This is an internal utility method which creates a end user when a user is created. */
export const finishEndUserOtpVerification = async verificationData => {
......@@ -458,3 +398,51 @@ export const updateActivityStatusAdmin = async ({ status, activityId, rejectionR
return response;
};
export const getCurrentEndUser = () => async dispatch => {
try {
console.log("here action");
const session = await getSession();
console.log("session action", session);
dispatch({
type: GET_END_USER_REQUEST
});
const config = {
headers: {
"Content-type": "application/json",
Authorization: `Bearer ${session.jwt}`
}
};
const query = {
populate: ["user"],
filter: {
user: {
id: {
$eq: session.id
}
}
}
};
const queryString = qs.stringify(query, {
encodeValuesOnly: true
});
console.log("querystring", query);
const response = await axios.get(`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/end-users/?${queryString}`, config);
console.log("response", response);
dispatch({
type: GET_END_USER_SUCCESS,
payload: response.data.data[0]
});
} catch (error) {
console.log("Error while fetching end user: ");
console.log(error);
dispatch({
type: GET_END_USER_FAIL,
payload: error.response.data
});
}
};
......@@ -19,4 +19,8 @@ export const RESET_PASSWORD_REQUEST = "RESET_PASSWORD_REQUEST";
export const RESET_PASSWORD_SUCCESS = "RESET_PASSWORD_SUCCESS";
export const RESET_PASSWORD_FAIL = "RESET_PASSWORD_FAIL";
export const GET_END_USER_REQUEST = "GET_END_USER_REQUEST";
export const GET_END_USER_SUCCESS = "GET_END_USER_SUCCESS";
export const GET_END_USER_FAIL = "GET_END_USER_FAIL";
export const CLEAR_ERRORS = 'CLEAR_ERRORS';
import { combineReducers } from "redux";
import { projectReducer, projectsReducer, similarProjectsReducer } from "./projectsReducer";
import { townshipReducer, townshipsReducer } from "./townshipsReducer";
import { authReducer, forgotPasswordReducer, loadedUserReducer, resetPasswordReducer, userReducer } from "./userReducers";
import { authReducer, forgotPasswordReducer, getEndUserReducer, loadedUserReducer, resetPasswordReducer, userReducer } from "./userReducers";
import { enquiryReducer } from "./enquiryReducer";
import { displayEnquireNowReducer } from "./enquireNowModalReducer";
import { getAllVendorsReducer, getVendorDetailsReducer, loggedInVendorReducer, updateVendorReducer } from "./vendorReducers";
......@@ -38,6 +38,7 @@ const reducers = combineReducers({
blog: blogReducer,
homeBanner: getAllHomeBannerReducer,
allVendors: getAllVendorsReducer,
endUser: getEndUserReducer,
});
export default reducers;
......@@ -15,7 +15,10 @@ import {
REGISTER_USER_REQUEST,
REGISTER_USER_SUCCESS,
REGISTER_USER_FAIL,
CLEAR_ERRORS
CLEAR_ERRORS,
GET_END_USER_FAIL,
GET_END_USER_SUCCESS,
GET_END_USER_REQUEST
} from "../constants/userConstants";
// Auth reducer
......@@ -183,3 +186,38 @@ export const resetPasswordReducer = (state = {}, action) => {
return state;
}
};
// Load user reducer
export const getEndUserReducer = (state = { loading: true, success: false, endUser: null }, action) => {
switch (action.type) {
case GET_END_USER_REQUEST:
return {
loading: true,
isAuthenticated: false
};
case GET_END_USER_SUCCESS:
return {
loading: false,
isAuthenticated: true,
endUser: action.payload
};
case GET_END_USER_FAIL:
return {
loading: false,
isAuthenticated: true,
error: action.payload.error.message
};
case CLEAR_ERRORS:
return {
...state,
error: null
};
default:
return state;
}
};
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!