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

Dynamic Dashboard Search #61

Open
wants to merge 8 commits into
base: main
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/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function App(): JSX.Element {
<Route exact path="/dashboard">
<Dashboard />
</Route>
<Route exact path="/profile" component={ProfileDetails} />
<Route path="/profile/*" component={ProfileDetails} />
<Route path="*">
<Redirect to="/login" />
</Route>
Expand Down
7 changes: 3 additions & 4 deletions client/src/components/NavBar/BecomeSitter/BecomeSitter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ const BecomeSitter = (): JSX.Element => {
};

const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setState({
...state,
setState((prevState) => ({
...prevState,
[event.target.name]: event.target.checked,
});
}));
};

const handleSitter = (event: ChangeEvent<HTMLInputElement>) => {
Expand All @@ -49,7 +49,6 @@ const BecomeSitter = (): JSX.Element => {

const handleSubmit = () => {
//TODO: Placeholder for editing profile info to switch between sitter and not a sitter
moffatethan marked this conversation as resolved.
Show resolved Hide resolved
console.log('hello');
setOpen(false);
};

Expand Down
38 changes: 24 additions & 14 deletions client/src/components/ProfileCard/ProfileCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,41 @@ import CardContent from '@mui/material/CardContent';
import Typography from '@mui/material/Typography';
import picture from '../../Images/d9fc84a0d1d545d77e78aaad39c20c11d3355074.png';
import { Profile } from '../../interface/Profile';
import { Link } from 'react-router-dom';

interface Props {
profile: Profile;
}

const ProfileCard = ({ profile }: Props): JSX.Element => {
const classes = useStyles();
const { _id: id, firstName, lastName, description, location, hourlyRate } = profile;

return (
<Card elevation={8} sx={{ minWidth: 245, maxWidth: 245, border: 2 }}>
<Box>
<img className={classes.picture} src={picture} />
</Box>
<Card
component={Link}
to={`/profile/${id}`}
elevation={8}
className={classes.profileCard}
sx={{ minWidth: 245, maxWidth: 245, minHeight: 350, maxHeight: 350 }}
>
<CardContent>
<Typography gutterBottom variant="h5" component="div">
{`${profile.firstName} ${profile.lastName}`}
</Typography>
<Typography variant="body2" color="text.secondary">
{profile.description}
</Typography>
<Box height={310} display={'flex'} flexDirection={'column'}>
<Box flexGrow={1}>
<img className={classes.picture} src={picture} />
<Typography gutterBottom variant="h5" component="div">
{`${firstName} ${lastName}`}
</Typography>
<Typography variant="body2" color="text.secondary">
{description}
</Typography>
</Box>
<Box display={'flex'} p={1} mt={5} justifyContent={'space-evenly'} className={classes.infoWrapper}>
<Typography>{location}</Typography>
<Typography>{`${hourlyRate}/hr`}</Typography>
</Box>
</Box>
</CardContent>
<Box className={classes.infoWrapper}>
<Typography>{profile.location}</Typography>
<Typography>$14/hr</Typography>
</Box>
</Card>
);
};
Expand Down
11 changes: 8 additions & 3 deletions client/src/components/ProfileCard/useStyles.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles((theme) => ({
profileCard: {
textDecoration: 'none',
overflow: 'hidden',
'&:hover': {
overflow: 'auto',
boxShadow: theme.shadows[23],
},
},
picture: {
borderRadius: '50%',
width: 150,
},
infoWrapper: {
borderTop: '1px solid grey',
display: 'flex',
padding: 5,
justifyContent: 'space-evenly',
},
}));

Expand Down
20 changes: 20 additions & 0 deletions client/src/helpers/APICalls/getAllProfiles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { FetchOptions } from '../../interface/FetchOptions';
import { AllProfilesApiData } from '../../interface/Profile';

const getAllProfiles = async (
searchValue: string | '',
startValue: Date | null,
endValue: Date | null,
): Promise<AllProfilesApiData> => {
const fetchOptions: FetchOptions = {
method: 'GET',
credentials: 'include',
};
return await fetch(`/profile/profiles?search=${searchValue}&start=${startValue}&end=${endValue}`, fetchOptions)
.then((res) => res.json())
.catch(() => ({
error: { message: 'Unable to connect to server. Please try again' },
}));
};

export default getAllProfiles;
65 changes: 45 additions & 20 deletions client/src/pages/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,44 @@ import CssBaseline from '@material-ui/core/CssBaseline';
import CircularProgress from '@material-ui/core/CircularProgress';
import useStyles from './useStyles';
import { useAuth } from '../../context/useAuthContext';
import { useSocket } from '../../context/useSocketContext';
import { useHistory } from 'react-router-dom';
import { useEffect } from 'react';
import { ChangeEvent, useEffect, useState } from 'react';
import { Box, Typography } from '@material-ui/core';
import ProfileCard from '../../components/ProfileCard/ProfileCard';
import { mockProfiles } from '../../mocks/mockProfile';
import getAllProfiles from '../../helpers/APICalls/getAllProfiles';
import { Profile } from '../../interface/Profile';
import DashboardSearch from './DashboardSearch/DashboardSearch';

export default function Dashboard(): JSX.Element {
const classes = useStyles();
const [profiles, setProfiles] = useState<Profile[]>([]);
const [searchValue, setSearchValue] = useState<string | ''>('');
const [startValue, setStartValue] = useState<Date | null>(new Date());
const [endValue, setEndValue] = useState<Date | null>(null);

const { loggedInUser } = useAuth();
const { initSocket } = useSocket();

const history = useHistory();

const handleSubmit = () => {
console.log('submitted');
useEffect(() => {
getAllProfiles(searchValue, startValue, endValue).then((data) => {
setProfiles(data.profiles);
});
}, [searchValue, startValue, endValue]);

const handleStartDateChange = (newValue: Date | null) => {
setStartValue(newValue);
};

useEffect(() => {
initSocket();
}, [initSocket]);
const handleEndDateChange = (newValue: Date | null) => {
setEndValue(newValue);
};

const handleSearchChange = (event: ChangeEvent<HTMLInputElement>) => {
setSearchValue(event.target.value);
};

if (loggedInUser === undefined) return <CircularProgress />;

if (!loggedInUser) {
history.push('/login');
// loading for a split seconds until history.push works
Expand All @@ -38,19 +52,30 @@ export default function Dashboard(): JSX.Element {
<CssBaseline />
<Grid item className={classes.searchWrapper}>
<Typography className={classes.searchText}>Search for Users</Typography>
<DashboardSearch
handleSearchChange={handleSearchChange}
handleStartDateChange={handleStartDateChange}
handleEndDateChange={handleEndDateChange}
startValue={startValue}
endValue={endValue}
/>
</Grid>
{/**TODO:
* 1. Each Card should be a link to the userprofile route
* 2. Currently using mock profiles, need to change to actual list of profiles from api call
**/}
*
* Currently using mock profiles, need to change to actual list of profiles from api call
***/}
<Grid container className={classes.listingsWrapper}>
{Array.from(mockProfiles).map((_, index) => (
<Grid item xs={4} key={index} className={classes.listingItem}>
<Box py={5} display={'flex'} justifyContent={'center'}>
<ProfileCard profile={mockProfiles[index]}></ProfileCard>
</Box>
</Grid>
))}
{profiles.length ? (
Array.from(profiles).map((_, index) => (
<Grid item xs={4} key={index} className={classes.listingItem}>
<Box py={2} display={'flex'} justifyContent={'center'}>
<ProfileCard profile={profiles[index]}></ProfileCard>
</Box>
</Grid>
))
) : (
<Box m={'auto'}>No users found.</Box>
)}
</Grid>
</Grid>
);
Expand Down
42 changes: 16 additions & 26 deletions client/src/pages/Dashboard/DashboardSearch/DashboardSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,32 @@ import MobileDatePicker from '@mui/lab/MobileDatePicker';
import { IconButton, Typography } from '@material-ui/core';
import { SearchOutlined } from '@material-ui/icons';

export default function DashboardSearch(): JSX.Element {
interface Props {
handleSearchChange: (event: ChangeEvent<HTMLInputElement>) => void;
handleStartDateChange: (newValue: Date | null) => void;
handleEndDateChange: (newValue: Date | null) => void;
startValue: Date | null;
endValue: Date | null;
}

export default function DashboardSearch({
handleSearchChange,
handleStartDateChange,
handleEndDateChange,
startValue,
endValue,
}: Props): JSX.Element {
const classes = useStyles();
const [cityValue, setCityValue] = useState<string | ''>('Search');
const [startValue, setStartValue] = useState<Date | null>(new Date());
const [endValue, setEndValue] = useState<Date | null>(new Date());
const initialDate = new Date();

const handleStartDateChange = (newValue: Date | null) => {
setStartValue(newValue);
};

const handleEndDateChange = (newValue: Date | null) => {
setEndValue(newValue);
};

const handleCityChange = (event: ChangeEvent<HTMLInputElement>) => {
setCityValue(event.target.value);
};

const handleKeyPress = (event: KeyboardEvent<HTMLDivElement>) => {
// TODO: Temp placeholder, contains values needed from search to be passed on.
if (event.key === 'Enter') {
event.preventDefault();
alert(`${cityValue}, ${startValue}, ${endValue}`);
}
};

return (
<Grid container justify={'center'}>
<Grid item>
<TextField
id="city"
label="Search by city"
variant="outlined"
onKeyPress={handleKeyPress}
onChange={handleCityChange}
onChange={handleSearchChange}
InputProps={{
startAdornment: (
<IconButton>
Expand Down
Loading