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

Added sorting functionality to ApartmentCards component, Added sortApartments.ts file. #353

Merged
merged 20 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
52b88bc
Add sorting functionality to ApartmentCards component on home page, l…
kea-roy Feb 25, 2024
9274837
Improved Dropdown component UI to more accurately match Figma design.…
kea-roy Feb 29, 2024
e7c1501
Improved ApartmentCards.tsx documentation and DropDown.tsx documentation
kea-roy Mar 1, 2024
dd6bac4
Fixed Dropdown Styling Layout on ApartmentPage.tsx
kea-roy Mar 4, 2024
c77402a
Revert "Fixed Dropdown Styling Layout on ApartmentPage.tsx"
kea-roy Mar 4, 2024
7c21aac
Removed bullet point on dropdown design after additional designer fee…
kea-roy Mar 9, 2024
07d8470
Merge branch 'main' into add-sorting-on-home-and-locations-part-two
ggsawatyanon Mar 24, 2024
2c790ef
Create DropDownWithLabel component and revamped all pages with dropdo…
kea-roy Apr 9, 2024
0af1be4
Merge branch 'add-sorting-on-home-and-locations-part-two' into sortin…
kea-roy Apr 9, 2024
46accb1
improved docs for dropdownwithlabel component
kea-roy Apr 9, 2024
89e93ba
Added animation for dropdown, adjusted code formatting for DropDown.t…
kea-roy Apr 16, 2024
1b1782d
Merge branch 'main' into add-sorting-on-home-and-locations-part-two
dan-ieljin Apr 17, 2024
34ea28e
Merge pull request #360 from cornell-dti/sorting-button-styling
dan-ieljin Apr 17, 2024
bf8ac5e
Merge branch 'main' into add-sorting-on-home-and-locations-part-two
kea-roy Apr 17, 2024
8bae035
Fixed issues with DropDown implementation on BookmarksPage and mobile…
kea-roy Apr 18, 2024
8706250
Merge branch 'main' into add-sorting-on-home-and-locations-part-two. …
kea-roy May 4, 2024
ce6dd2c
resolved compile warnings
kea-roy May 4, 2024
9d996c7
Merge branch 'main' into add-sorting-on-home-and-locations-part-two
ggsawatyanon May 5, 2024
0c920e1
Adjusted dropdown styling and size in DropDown and DropDownWithLabel …
kea-roy May 6, 2024
cb31115
fixed review modal drop down
ggsawatyanon May 13, 2024
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
1 change: 1 addition & 0 deletions frontend/src/assets/dropdown-arrow-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 91 additions & 27 deletions frontend/src/components/ApartmentCard/ApartmentCards.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React, { ReactElement, useState } from 'react';
import React, { ReactElement, useEffect, useState } from 'react';
import ApartmentCard from './ApartmentCard';
import { Grid, Link, makeStyles, Button } from '@material-ui/core';
import { Link as RouterLink } from 'react-router-dom';
import { CardData } from '../../App';
import { loadingLength } from '../../constants/HomeConsts';
import { ApartmentWithId } from '../../../../common/types/db-types';
import { sortApartments } from '../../utils/sortApartments';
import DropDownWithLabel from '../utils/DropDownWithLabel';

type Props = {
data: CardData[];
Expand Down Expand Up @@ -36,8 +39,10 @@ const useStyles = makeStyles({
/**
* ApartmentCards Component
*
* This component displays ApartmentCard components of the data. It also shows
* a 'Show more' button if there is more data than the loadingLength constant.
* @remarks
* This component displays ApartmentCard components of the data.
* It also shows a 'Show more' button if there is more data than the loadingLength constant.
* It also has a dropdown to sort the apartments based on different properties, such as price and rating.
* The component is responsive and adjusts its layout based on the screen size.
*
* @component
Expand All @@ -47,40 +52,99 @@ const useStyles = makeStyles({
*/
const ApartmentCards = ({ data, user, setUser }: Props): ReactElement => {
const { boundingBox, showMoreButton, horizontalLine } = useStyles();

const [isMobile, setIsMobile] = useState<boolean>(false);
const [resultsToShow, setResultsToShow] = useState<number>(loadingLength);

const handleShowMore = () => {
setResultsToShow(resultsToShow + loadingLength);
};

// Handle resizing of the window depending on mobile and if it is clicked.
useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth <= 600);
};
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

type Fields = keyof CardData | keyof ApartmentWithId | 'originalOrder';
const [sortBy, setSortBy] = useState<Fields>('originalOrder');
const [orderLowToHigh, setOrderLowToHigh] = useState<boolean>(false);

return (
<>
<Grid item style={{ marginRight: '8px' }}>
<DropDownWithLabel
label="Sort by"
menuItems={[
{
item: 'Recommended',
callback: () => {
setSortBy('originalOrder');
setOrderLowToHigh(false);
},
},
{
item: 'Lowest Price',
callback: () => {
setSortBy('avgPrice');
setOrderLowToHigh(true);
},
},
{
item: 'Highest Price',
callback: () => {
setSortBy('avgPrice');
setOrderLowToHigh(false);
},
},
{
item: 'Lowest Rating',
callback: () => {
setSortBy('avgRating');
setOrderLowToHigh(true);
},
},
{
item: 'Highest Rating',
callback: () => {
setSortBy('avgRating');
setOrderLowToHigh(false);
},
},
]}
isMobile={isMobile}
/>
</Grid>
<Grid container spacing={3} className={boundingBox}>
{data &&
data.slice(0, resultsToShow).map(({ buildingData, numReviews, company }, index) => {
const { id } = buildingData;
return (
<Grid item md={12} key={index}>
<Link
{...{
to: `/apartment/${id}`,
style: { textDecoration: 'none' },
component: RouterLink,
}}
>
<ApartmentCard
key={index}
numReviews={numReviews}
buildingData={buildingData}
company={company}
user={user}
setUser={setUser}
/>
</Link>
</Grid>
);
})}
sortApartments(data, sortBy, orderLowToHigh)
.slice(0, resultsToShow)
.map(({ buildingData, numReviews, company }, index) => {
const { id } = buildingData;
return (
<Grid item md={12} key={index}>
<Link
{...{
to: `/apartment/${id}`,
style: { textDecoration: 'none' },
component: RouterLink,
}}
>
<ApartmentCard
key={index}
numReviews={numReviews}
buildingData={buildingData}
company={company}
user={user}
setUser={setUser}
/>
</Link>
</Grid>
);
})}

{data && data.length > resultsToShow && (
<>
Expand Down
13 changes: 4 additions & 9 deletions frontend/src/components/LeaveReview/ReviewModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
makeStyles,
IconButton,
CardMedia,
Icon,
useMediaQuery,
} from '@material-ui/core';
import axios from 'axios';
Expand Down Expand Up @@ -69,18 +68,14 @@ const useStyle = makeStyles({
fontWeight: 600,
width: '100%',
height: '100%',
borderRadius: '50px !important',
backgroundColor: 'transparent',
top: '0',
left: '0',
textTransform: 'none',
fontSize: '18px',
textAlign: 'left',
position: 'absolute',
zIndex: 1,
display: 'flex',
justifyContent: 'left',
paddingLeft: '25px',
borderRadius: '50px',
justifyContent: 'flex-start',
paddingLeft: '20px',
},
expandMoreIcon: {
right: '10px',
Expand Down Expand Up @@ -515,7 +510,7 @@ const ReviewModal = ({
spacing={1}
direction="row"
alignItems="center"
justifyContent="flex-start"
justifyContent={isMobile ? 'flex-start' : 'flex-end'}
>
<Grid
item
Expand Down
77 changes: 60 additions & 17 deletions frontend/src/components/utils/DropDown.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,48 @@
import React, { useState, useEffect } from 'react';
import { Button, Menu, MenuItem } from '@material-ui/core';
import { makeStyles } from '@material-ui/styles';
/**
* DropDown Component
*
* @remarks
* A dropdown component that displays a button and a menu with selectable items.
* The component uses Material-UI components for consistent styling.
*
* @component
* @example
* ```typescript
* const menuItems = [
* { item: 'Price', callback: () => setSortBy('avgPrice')},
* { item: 'Rating', callback: () => setSortBy('avgRating')},
* { item: 'Date Added', callback: () => setSortBy('id')},
* ];
*
* function App() {
* return (
* <DropDown menuItems={menuItems} />
* );
* }
*```
* @param {Object} props - The props of the component.
* @param {MenuElement[]} props.menuItems - An array of menu items, each containing an item name and a callback function.
* @returns {JSX.Element} The rendered dropdown component.
*/
import React, { useState } from 'react';
import { Button, Menu, MenuItem, SvgIcon } from '@material-ui/core';
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
import SvgIcon from '@material-ui/core/SvgIcon';
import { makeStyles } from '@material-ui/styles';
import ArrowDownSrc from '../../assets/dropdown-arrow-down.svg';

const expandArrow = (direction: boolean) => {
return (
<div
style={{
padding: '0 0 0 10px',
transform: direction ? 'scaleY(-1)' : 'none',
transition: 'all 0.5s ease',
}}
>
<img src={ArrowDownSrc} alt="⬇" height="10" />
</div>
);
};

type MenuElement = {
item: string;
Expand All @@ -11,24 +51,31 @@ type MenuElement = {

type Props = {
menuItems: MenuElement[];
isMobile?: boolean;
defaultValue?: string;
className?: string;
icon?: boolean;
};

const useStyles = makeStyles({
button: {
minWidth: '64px',
backgroundColor: '#e8e8e8',
borderColor: '#e8e8e8',
borderColor: '#E8E8E8',
textTransform: 'none',
fontSize: '18px',
lineHeight: 'normal',
fontWeight: 'normal',
height: '44px',
borderRadius: '10px',
backgroundColor: '#E8E8E8',
scale: '1',
whiteSpace: 'nowrap',
},
});

export default function BasicMenu({ menuItems, defaultValue, className, icon }: Props) {
export default function DropDown({ menuItems, isMobile, defaultValue, className, icon }: Props) {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [selected, setSelected] = useState<string>(defaultValue ? defaultValue : 'Recent');
const [selected, setSelected] = useState<string>(defaultValue ? defaultValue : menuItems[0].item);
const { button } = useStyles();
const [isMobile, setIsMobile] = useState<boolean>(false);

const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
Expand All @@ -37,12 +84,6 @@ export default function BasicMenu({ menuItems, defaultValue, className, icon }:
const handleClose = () => {
setAnchorEl(null);
};
useEffect(() => {
const handleResize = () => setIsMobile(window.innerWidth <= 600);
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

return (
<div>
Expand All @@ -55,7 +96,9 @@ export default function BasicMenu({ menuItems, defaultValue, className, icon }:
className={className || button}
>
{selected}
{icon != false && <SvgIcon component={ArrowDropDownIcon} />}
{icon === undefined
? expandArrow(open)
: icon === true && <SvgIcon component={ArrowDropDownIcon} />}
</Button>
<Menu
id="basic-menu"
Expand Down
74 changes: 74 additions & 0 deletions frontend/src/components/utils/DropDownWithLabel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* A dropdown component with a label.
*
* @component
*
* @param {string} label - The label for the dropdown.
* @param {MenuElement[]} menuItems - An array of menu items, each containing an item name and a callback function.
* @param {React.CSSProperties} [labelStyle] - The style of the label.
* @param {boolean} isMobile - Whether the dropdown is being displayed on a mobile device.
*
* @returns {JSX.Element} The rendered dropdown component.
*
* @example
* // Usage:
* const menuItems = [
* { item: 'Item 1', callback: () => console.log('Item 1 selected') },
* { item: 'Item 2', callback: () => console.log('Item 2 selected') },
* { item: 'Item 3', callback: () => console.log('Item 3 selected') },
* ];
*
* <DropDownWithLabel label="Select an item" menuItems={menuItems} isMobile={true} />
*/
import React from 'react';
import { Typography, Grid } from '@material-ui/core';
import DropDown from './DropDown';

type MenuElement = {
item: string;
callback: () => void;
};

interface DropDownWithLabelProps {
label: string;
menuItems: MenuElement[];
labelStyle?: React.CSSProperties;
isMobile: boolean;
}

const DropDownWithLabel: React.FC<DropDownWithLabelProps> = ({
label,
menuItems,
labelStyle,
isMobile,
}) => {
return (
<Grid
container
direction="row"
alignItems="center"
justifyContent="flex-end"
wrap="nowrap"
spacing={0}
>
<Grid item>
<Typography
variant="body1"
style={{
fontSize: '18px',
paddingRight: '10px',
whiteSpace: 'nowrap',
...labelStyle,
}}
>
{label}
</Typography>
</Grid>
<Grid item>
<DropDown menuItems={menuItems} isMobile={isMobile} />
</Grid>
</Grid>
);
};

export default DropDownWithLabel;
Loading
Loading