Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Profile details IN with BE #70

Open
wants to merge 3 commits into
base: profile_listings_IN
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/src/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const Routes = (): JSX.Element => {
<ProtectedRoute exact path="/dashboard" component={ProfileListings} />
<ProtectedRoute exact path="/settings" component={Settings} />
<ProtectedRoute exact path="/messages" component={Messages} />
<ProtectedRoute path="/dashboard/:profileId" component={ProfileDetails} />
<ProtectedRoute path="/dashboard/:userId" component={ProfileDetails} />
<Route path="*">
<Redirect to="/login" />
</Route>
Expand Down
36 changes: 13 additions & 23 deletions client/src/components/ProfileDetail/ProfileDetailCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,50 @@ 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 {
const classes = useStyles();
return (
<Card className={classes.cardContainer}>
<CardMedia
image={profile.coverImg ? profile.coverImg : defaultCoverImg}
image={profile.profileId[0]?.coverImg ? profile.profileId[0].coverImg : defaultCoverImg}
title="Contemplative Reptile"
className={classes.coverImg}
/>
<CardMedia
image={profile.profileImg ? profile.profileImg : defaultProfileImg}
image={profile.profileId[0]?.profileImg ? profile.profileId[0].profileImg : defaultProfileImg}
title="Contemplative Reptile"
className={classes.profileImg}
/>
<CardContent className={classes.cardContent}>
<Typography variant="h4" className={classes.profileName}>
<Typography variant="h4" component="h1" className={classes.profileName}>
{profile.firstName} {profile.lastName}
</Typography>
<Typography variant="h6" color="textSecondary" className={classes.subInfo}>
<Typography variant="h6" component="h2" color="textSecondary" className={classes.subInfo}>
Loving pet sitter
</Typography>
{profile.address && (
{profile.profileId[0]?.city && (
<Box className={classes.profileLocation}>
<LocationOnIcon color="primary" />
<Typography component="span" display="block">
{profile.address}
{profile.profileId[0].city}
</Typography>
</Box>
)}
<Box className={classes.introduction}>
{profile.description && (
{profile.profileId[0]?.description && (
<Box>
<Typography variant="h5">About me</Typography>
<Typography variant="subtitle1">{profile.description}</Typography>
<Typography variant="h5" component="h3">
About me
</Typography>
<Typography variant="subtitle1">{profile.profileId[0].description}</Typography>
</Box>
)}
<Box>
{profile.galleryImg?.map((image, index) => {
<CardMedia key={index} image={image} />;
})}
</Box>
</Box>
</CardContent>
</Card>
Expand Down
186 changes: 123 additions & 63 deletions client/src/components/ProfileDetail/RequestCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<FormValues>): 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 (
<>
<Box textAlign="center">
<Typography variant="h4">{`${profile.priceRate}/hr`}</Typography>
<Rating value={4.2} />
</Box>
<Grid container>
<Grid item xs={12}>
<InputLabel htmlFor="dropIn" className={classes.inputLabel}>
Drop In
</InputLabel>
</Grid>
<Grid item xs={12} className={classes.inputFieldsContainer}>
<TextField
type="date"
id="dropIn"
name="dropIn"
variant="outlined"
inputProps={{
min: format(new Date(), 'yyyy-MM-dd'),
}}
// sadas
/>
<TextField
type="time"
id="dropInTime"
name="dropInTime"
variant="outlined"
// sadas
/>
</Grid>
<Grid item xs={12}>
<InputLabel htmlFor="dropOff" className={classes.inputLabel}>
Drop Off
</InputLabel>
</Grid>
<Grid item xs={12} className={classes.inputFieldsContainer}>
<TextField
type="date"
id="dropOff"
name="dropOff"
variant="outlined"
inputProps={{
min: format(new Date(), 'yyyy-MM-dd'),
}}
/>
<TextField
type="time"
id="dropOffTime"
name="dropOffTime"
variant="outlined"
// sadas
/>
</Grid>
</Grid>
<Box textAlign="center" className={classes.buttonContainer}>
<Button type="submit" size="large" variant="contained" color="primary">
Send Request
</Button>
<Button type="button" size="large" variant="contained" color="primary">
Send Message
</Button>
<Typography variant="h4">{`$${profile.profileId[0]?.priceRate}/hr`}</Typography>
</Box>
<Formik
initialValues={{
start_date: '',
end_date: '',
dropInTime: '',
dropOffTime: '',
}}
validationSchema={Yup.object().shape({
start_date: Yup.string().required('Drop In Date is required'),
end_date: Yup.string().required('Drop Off Date is required'),
})}
onSubmit={handleSubmit}
>
{({ handleSubmit, handleChange, values, touched, errors, isSubmitting }) => (
<form onSubmit={handleSubmit} noValidate>
<Grid container>
<Grid item xs={12}>
<InputLabel htmlFor="start_date" className={classes.inputLabel}>
Drop In
</InputLabel>
</Grid>
<Grid item xs={12} className={classes.inputFieldsContainer}>
<TextField
type="date"
id="start_date"
name="start_date"
variant="outlined"
inputProps={{
min: format(new Date(), 'yyyy-MM-dd'),
}}
helperText={touched.start_date ? errors.start_date : ''}
error={touched.start_date && Boolean(errors.start_date)}
value={values.start_date}
onChange={handleChange}
/>
<TextField
type="time"
id="dropInTime"
name="dropInTime"
variant="outlined"
helperText={touched.dropInTime ? errors.dropInTime : ''}
error={touched.dropInTime && Boolean(errors.dropInTime)}
value={values.dropInTime}
onChange={handleChange}
/>
</Grid>
<Grid item xs={12}>
<InputLabel htmlFor="end_date" className={classes.inputLabel}>
Drop Off
</InputLabel>
</Grid>
<Grid item xs={12} className={classes.inputFieldsContainer}>
<TextField
type="date"
id="end_date"
name="end_date"
variant="outlined"
inputProps={{
min: format(new Date(), 'yyyy-MM-dd'),
}}
helperText={touched.end_date ? errors.end_date : ''}
error={touched.end_date && Boolean(errors.end_date)}
value={values.end_date}
onChange={handleChange}
/>
<TextField
type="time"
id="dropOffTime"
name="dropOffTime"
variant="outlined"
helperText={touched.dropOffTime ? errors.dropOffTime : ''}
error={touched.dropOffTime && Boolean(errors.dropOffTime)}
value={values.dropOffTime}
onChange={handleChange}
/>
</Grid>
</Grid>
<Box textAlign="center" className={classes.buttonContainer}>
<Button type="submit" size="large" variant="contained" color="primary">
{isSubmitting ? <CircularProgress style={{ color: 'white' }} /> : 'Send Request'}
</Button>
<Button type="button" size="large" variant="contained" color="primary">
Send Message
</Button>
</Box>
</form>
)}
</Formik>
</>
);
}
1 change: 1 addition & 0 deletions client/src/components/ProfileDetail/useStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const useStyles = makeStyles((theme) => ({
},
subInfo: {
marginBottom: '20px',
fontSize: '0.8rem',
},
profileLocation: {
marginBottom: '1rem',
Expand Down
27 changes: 26 additions & 1 deletion client/src/helpers/APICalls/getProfiles.ts
Original file line number Diff line number Diff line change
@@ -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<ProfilesApiData> => {
const fetchOptions: FetchOptions = {
Expand All @@ -13,4 +13,29 @@ const getProfiles = async (): Promise<ProfilesApiData> => {
}));
};

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;
16 changes: 16 additions & 0 deletions client/src/helpers/APICalls/request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { FetchOptions } from '../../interface/FetchOptions';
import { RequestApiData, Request } from '../../interface/Request';

export const createRequest = async (data: Request): Promise<RequestApiData> => {
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' },
}));
};
1 change: 0 additions & 1 deletion client/src/interface/Profile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { User } from './User';
import { IUserContext } from '../context/useUserContext';

export interface IProfile extends IUserContext {
Expand Down
11 changes: 11 additions & 0 deletions client/src/interface/Request.ts
Original file line number Diff line number Diff line change
@@ -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;
}
Loading