From dbdb060aedd6f75bfde2dd9f84266f3d3a72d5de Mon Sep 17 00:00:00 2001 From: gurkiran_singh Date: Wed, 23 Jun 2021 00:34:53 -0400 Subject: [PATCH 1/2] AddedRequest details IN Signed-off-by: gurkiran_singh --- client/src/Routes.tsx | 2 +- .../ProfileDetail/ProfileDetailCard.tsx | 36 ++-- .../components/ProfileDetail/RequestCard.tsx | 186 ++++++++++++------ .../src/components/ProfileDetail/useStyles.ts | 1 + client/src/helpers/APICalls/getProfiles.ts | 27 ++- client/src/helpers/APICalls/request.ts | 16 ++ client/src/interface/Profile.ts | 1 - client/src/interface/Request.ts | 11 ++ .../pages/ProfileDetails/ProfileDetails.tsx | 50 +++-- .../src/pages/ProfileListings/ProfileCard.tsx | 2 +- server/controllers/profile.js | 34 ++++ server/controllers/request.js | 1 + server/routes/profile.js | 5 +- server/validate.js | 3 - 14 files changed, 264 insertions(+), 111 deletions(-) create mode 100644 client/src/helpers/APICalls/request.ts create mode 100644 client/src/interface/Request.ts diff --git a/client/src/Routes.tsx b/client/src/Routes.tsx index 0d298c9..92f6f09 100644 --- a/client/src/Routes.tsx +++ b/client/src/Routes.tsx @@ -23,7 +23,7 @@ const Routes = (): JSX.Element => { - + diff --git a/client/src/components/ProfileDetail/ProfileDetailCard.tsx b/client/src/components/ProfileDetail/ProfileDetailCard.tsx index 693f8d1..c8a9534 100644 --- a/client/src/components/ProfileDetail/ProfileDetailCard.tsx +++ b/client/src/components/ProfileDetail/ProfileDetailCard.tsx @@ -4,17 +4,10 @@ import { Box, Card, CardContent, CardMedia, Typography } from '@material-ui/core import defaultCoverImg from '../../Images/default-profile-detail-cover.jpg'; import defaultProfileImg from '../../Images/default-profile-image.jpg'; import useStyles from './useStyles'; +import { Profile } from '../../pages/ProfileListings/ProfileListings'; interface Props { - profile: { - coverImg: string; - profileImg: string; - firstName: string; - lastName: string; - address: string; - description: string; - galleryImg: [string] | null; - }; + profile: Profile; } export default function ProfileDetailCard({ profile }: Props): JSX.Element { @@ -22,42 +15,39 @@ export default function ProfileDetailCard({ profile }: Props): JSX.Element { return ( - + {profile.firstName} {profile.lastName} - + Loving pet sitter - {profile.address && ( + {profile.profileId.city && ( - {profile.address} + {profile.profileId.city} )} - {profile.description && ( + {profile.profileId.description && ( - About me - {profile.description} + + About me + + {profile.profileId.description} )} - - {profile.galleryImg?.map((image, index) => { - ; - })} - diff --git a/client/src/components/ProfileDetail/RequestCard.tsx b/client/src/components/ProfileDetail/RequestCard.tsx index 087d77d..cc0aefb 100644 --- a/client/src/components/ProfileDetail/RequestCard.tsx +++ b/client/src/components/ProfileDetail/RequestCard.tsx @@ -3,83 +3,143 @@ import Box from '@material-ui/core/Box'; import Button from '@material-ui/core/Button'; import Grid from '@material-ui/core/Grid'; import TextField from '@material-ui/core/TextField'; +import CircularProgress from '@material-ui/core/CircularProgress'; import Typography from '@material-ui/core/Typography'; import InputLabel from '@material-ui/core/InputLabel'; -import { Rating } from '@material-ui/lab'; +import { Formik, FormikHelpers } from 'formik'; +import * as Yup from 'yup'; import useStyles from './useStyles'; +import { Profile } from '../../pages/ProfileListings/ProfileListings'; +import { useSnackBar } from '../../context/useSnackbarContext'; +import { useAuth } from '../../context/useAuthContext'; +import { createRequest } from '../../helpers/APICalls/request'; interface Props { - profile: { - priceRate: number; - }; + profile: Profile; +} + +interface FormValues { + start_date: string; + end_date: string; + dropInTime: string; + dropOffTime: string; } + export default function RequestCard({ profile }: Props): JSX.Element { const classes = useStyles(); + const { updateSnackBarMessage } = useSnackBar(); + const { loggedInUser } = useAuth(); + + const handleSubmit = (values: FormValues, { setSubmitting }: FormikHelpers): void => { + const { start_date, end_date } = values; + const user_id = loggedInUser?._id ? loggedInUser._id : ''; + const sitter_id = profile._id; + + createRequest({ start_date, end_date, sitter_id, user_id }).then((data) => { + if (data.error) { + updateSnackBarMessage(data.error); + setSubmitting(false); + } else if (data.success) { + updateSnackBarMessage(data.success); + setSubmitting(false); + } + }); + }; return ( <> - {`${profile.priceRate}/hr`} - - - - - - Drop In - - - - - - - - - Drop Off - - - - - - - - - - + {`$${profile.profileId.priceRate}/hr`} + + {({ handleSubmit, handleChange, values, touched, errors, isSubmitting }) => ( +
+ + + + Drop In + + + + + + + + + Drop Off + + + + + + + + + + + +
+ )} +
); } diff --git a/client/src/components/ProfileDetail/useStyles.ts b/client/src/components/ProfileDetail/useStyles.ts index 0073295..be4cbe2 100644 --- a/client/src/components/ProfileDetail/useStyles.ts +++ b/client/src/components/ProfileDetail/useStyles.ts @@ -41,6 +41,7 @@ const useStyles = makeStyles((theme) => ({ }, subInfo: { marginBottom: '20px', + fontSize: '0.8rem', }, profileLocation: { marginBottom: '1rem', diff --git a/client/src/helpers/APICalls/getProfiles.ts b/client/src/helpers/APICalls/getProfiles.ts index 3cc3e0d..363795d 100644 --- a/client/src/helpers/APICalls/getProfiles.ts +++ b/client/src/helpers/APICalls/getProfiles.ts @@ -1,5 +1,5 @@ import { FetchOptions } from '../../context/interface/FetchOptions'; -import { ProfilesApiData } from '../../interface/Profile'; +import { ProfilesApiData, IProfile } from '../../interface/Profile'; const getProfiles = async (): Promise => { const fetchOptions: FetchOptions = { @@ -13,4 +13,29 @@ const getProfiles = async (): Promise => { })); }; +export const getOneFullUserProfile = async ( + userId: string, +): Promise<{ + user?: { + firstName: string; + lastName: string; + isDogSitter: boolean; + email: string; + _id: string; + profileId: IProfile; + }; + success?: string; + error?: string; +}> => { + const fetchOptions: FetchOptions = { + method: 'GET', + credentials: 'include', + }; + return await fetch(`/profile/${userId}`, fetchOptions) + .then((res) => res.json()) + .catch(() => ({ + error: { message: 'Unable to connect to server. Please try again' }, + })); +}; + export default getProfiles; diff --git a/client/src/helpers/APICalls/request.ts b/client/src/helpers/APICalls/request.ts new file mode 100644 index 0000000..000b35c --- /dev/null +++ b/client/src/helpers/APICalls/request.ts @@ -0,0 +1,16 @@ +import { FetchOptions } from '../../interface/FetchOptions'; +import { RequestApiData, Request } from '../../interface/Request'; + +export const createRequest = async (data: Request): Promise => { + const fetchOptions: FetchOptions = { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ ...data }), + credentials: 'include', + }; + return await fetch(`/request/create`, fetchOptions) + .then((res) => res.json()) + .catch(() => ({ + error: { message: 'Unable to connect to server. Please try again' }, + })); +}; diff --git a/client/src/interface/Profile.ts b/client/src/interface/Profile.ts index 4f315bb..3c33238 100644 --- a/client/src/interface/Profile.ts +++ b/client/src/interface/Profile.ts @@ -1,4 +1,3 @@ -import { User } from './User'; import { IUserContext } from '../context/useUserContext'; export interface IProfile extends IUserContext { diff --git a/client/src/interface/Request.ts b/client/src/interface/Request.ts new file mode 100644 index 0000000..56a7002 --- /dev/null +++ b/client/src/interface/Request.ts @@ -0,0 +1,11 @@ +export interface Request { + user_id: string; + sitter_id: string; + start_date: string; + end_date: string; +} + +export interface RequestApiData { + success?: string; + error?: string; +} \ No newline at end of file diff --git a/client/src/pages/ProfileDetails/ProfileDetails.tsx b/client/src/pages/ProfileDetails/ProfileDetails.tsx index 97dff0b..53a1404 100644 --- a/client/src/pages/ProfileDetails/ProfileDetails.tsx +++ b/client/src/pages/ProfileDetails/ProfileDetails.tsx @@ -1,36 +1,52 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import Paper from '@material-ui/core/Paper'; import Grid from '@material-ui/core/Grid'; +import { RouteComponentProps } from 'react-router-dom'; import useStyles from './useStyles'; +import Spinner from '../../components/Spinner/Spinner'; +import { useSnackBar } from '../../context/useSnackbarContext'; import ProfileDetailCard from '../../components/ProfileDetail/ProfileDetailCard'; import RequestCard from '../../components/ProfileDetail/RequestCard'; +import { Profile } from '../ProfileListings/ProfileListings'; +import { getOneFullUserProfile } from '../../helpers/APICalls/getProfiles'; -export default function ProfileDetails(): JSX.Element { +interface StateProps { + previousPath?: string; + profile?: Profile; +} + +export default function ProfileDetails({ location, match }: RouteComponentProps): JSX.Element { const classes = useStyles(); + const { updateSnackBarMessage } = useSnackBar(); + const state = location.state as StateProps; + const [profile, setProfile] = useState(null); - //testing data - const [profile, setProfile] = useState({ - coverImg: '', - profileImg: '', - firstName: 'Norma', - lastName: 'Byers', - address: 'Toronto, Ontario', - description: 'This is testing decription', - galleryImg: null, - priceRate: 14, - }); + useEffect(() => { + if (state.profile) { + setProfile(state.profile); + } else { + const params = match.params as { userId: string }; + getOneFullUserProfile(params.userId).then((data) => { + if (data.error) { + updateSnackBarMessage(data.error); + } else if (data.success) { + if (data.user) { + setProfile(data.user); + } + } + }); + } + }, [match]); return ( - - - + {profile ? : } - + {profile ? : } diff --git a/client/src/pages/ProfileListings/ProfileCard.tsx b/client/src/pages/ProfileListings/ProfileCard.tsx index f51a442..49575d4 100644 --- a/client/src/pages/ProfileListings/ProfileCard.tsx +++ b/client/src/pages/ProfileListings/ProfileCard.tsx @@ -21,7 +21,7 @@ const ProfileCard: React.FC = ({ profile }) => { return ( diff --git a/server/controllers/profile.js b/server/controllers/profile.js index e40aebb..980c964 100644 --- a/server/controllers/profile.js +++ b/server/controllers/profile.js @@ -107,6 +107,40 @@ exports.createProfile = asyncHandler(async (req, res, next) => { }) +exports.getOneFullUserProfile = asyncHandler(async (req, res, next) => { + const userId = req.params.userId; + // validate id + if (!ObjectId.isValid(userId)) { + return res.status(400).send(Error("User ID is invalid.")); + }; + + try { + const user = await User.findOne({ + _id: userId, + isDogSitter: { $eq: true }, + profileId: { + $exists: true, + }, + }) + .select("firstName lastName email isDogSitter") + .populate({ + path: "profileId", + select: "-__v -availableDays" + }); + + return res.status(400).json({ + success: 'Retrieved successfully', + user + }) + + } catch (error) { + res.status(500).json({ + error: error.message + }) + } + +}) + // @route GET /profile/ exports.getOneProfile = asyncHandler(async (req, res, next) => { diff --git a/server/controllers/request.js b/server/controllers/request.js index f73ff84..d618266 100644 --- a/server/controllers/request.js +++ b/server/controllers/request.js @@ -55,6 +55,7 @@ exports.createRequest = (req, res) => { } return res.status(200).json({ + success: "Request send successfully.", request }) diff --git a/server/routes/profile.js b/server/routes/profile.js index d16b277..ba3b91c 100644 --- a/server/routes/profile.js +++ b/server/routes/profile.js @@ -8,7 +8,8 @@ const { getOneProfile, getAllProfiles, getProfilesBySearch, - getProfilesByDay + getProfilesByDay, + getOneFullUserProfile } = require('../controllers/profile'); @@ -16,6 +17,8 @@ router.post("/createorupdate", validateCreateProfile, protect, createProfile); router.get("/one", protect, getOneProfile); +router.get("/:userId", protect, getOneFullUserProfile); + router.get("/", protect, getAllProfiles); router.get("/search/city/:search", protect, getProfilesBySearch); diff --git a/server/validate.js b/server/validate.js index c11eade..962fb16 100755 --- a/server/validate.js +++ b/server/validate.js @@ -45,9 +45,6 @@ exports.validateCreateProfile = [ ] exports.validateCreateRequest = [ - check("user_id") - .isMongoId() - .withMessage("User Id must be valid mongo Object Id"), check("sitter_id") .isMongoId() .withMessage("User Id must be valid mongo Object Id"), From 8fe59c330a7e4c5ea533f731ae76fb8489d61ad6 Mon Sep 17 00:00:00 2001 From: gurkiran_singh Date: Fri, 25 Jun 2021 03:12:07 -0400 Subject: [PATCH 2/2] Added changes related to fetching profile id with [] Signed-off-by: gurkiran_singh --- .../components/ProfileDetail/ProfileDetailCard.tsx | 12 ++++++------ client/src/components/ProfileDetail/RequestCard.tsx | 2 +- client/src/helpers/APICalls/getProfiles.ts | 2 +- server/controllers/profile.js | 7 ++++++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/client/src/components/ProfileDetail/ProfileDetailCard.tsx b/client/src/components/ProfileDetail/ProfileDetailCard.tsx index c8a9534..338035a 100644 --- a/client/src/components/ProfileDetail/ProfileDetailCard.tsx +++ b/client/src/components/ProfileDetail/ProfileDetailCard.tsx @@ -15,12 +15,12 @@ export default function ProfileDetailCard({ profile }: Props): JSX.Element { return ( @@ -31,21 +31,21 @@ export default function ProfileDetailCard({ profile }: Props): JSX.Element { Loving pet sitter - {profile.profileId.city && ( + {profile.profileId[0]?.city && ( - {profile.profileId.city} + {profile.profileId[0].city} )} - {profile.profileId.description && ( + {profile.profileId[0]?.description && ( About me - {profile.profileId.description} + {profile.profileId[0].description} )} diff --git a/client/src/components/ProfileDetail/RequestCard.tsx b/client/src/components/ProfileDetail/RequestCard.tsx index cc0aefb..7e18545 100644 --- a/client/src/components/ProfileDetail/RequestCard.tsx +++ b/client/src/components/ProfileDetail/RequestCard.tsx @@ -50,7 +50,7 @@ export default function RequestCard({ profile }: Props): JSX.Element { return ( <> - {`$${profile.profileId.priceRate}/hr`} + {`$${profile.profileId[0]?.priceRate}/hr`} { $exists: true, }, }) + .lean() .select("firstName lastName email isDogSitter") .populate({ path: "profileId", select: "-__v -availableDays" }); + const newProfileId = [{...user.profileId}]; + const newUser = user; + newUser.profileId = newProfileId + return res.status(400).json({ success: 'Retrieved successfully', - user + user: newUser }) } catch (error) {