From c5e6237503a31ed48068999eca6de87d951df5f2 Mon Sep 17 00:00:00 2001 From: Lauren Pothuru Date: Wed, 5 Nov 2025 19:19:04 -0500 Subject: [PATCH 1/3] Implement clicking into map pins --- .../Apartment/MarkerWithAptCard.tsx | 74 +++++++++++-------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/frontend/src/components/Apartment/MarkerWithAptCard.tsx b/frontend/src/components/Apartment/MarkerWithAptCard.tsx index 6c7d1438..3c38fa6d 100644 --- a/frontend/src/components/Apartment/MarkerWithAptCard.tsx +++ b/frontend/src/components/Apartment/MarkerWithAptCard.tsx @@ -3,6 +3,8 @@ import { CardData } from '../../App'; import aptIcon from '../../assets/location-pin.svg'; import mapPinIcon from '../../assets/map-pin.svg'; import NewApartmentCard from '../ApartmentCard/NewApartmentCard'; +import { Link as RouterLink, useHistory } from 'react-router-dom'; +import { Link } from '@material-ui/core'; type markerWithCardProp = { readonly lat: number; @@ -60,41 +62,49 @@ export const MapMarkerWithCard = ({ }, 100) } > - {apt.buildingData.name} - {hoveredIdx === idx && ( -
+ {apt.buildingData.name} setCardHovered(true)} - onMouseLeave={() => { - setCardHovered(false); - setHoveredIdx(null); - }} - > - -
- )} + /> + {hoveredIdx === idx && ( +
setCardHovered(true)} + onMouseLeave={() => { + setCardHovered(false); + setHoveredIdx(null); + }} + > + +
+ )} + ); }; From f7ab07c8dfa65a480cc9dfcfba26593ef3749b4d Mon Sep 17 00:00:00 2001 From: Lauren Pothuru Date: Thu, 6 Nov 2025 15:53:29 -0500 Subject: [PATCH 2/3] Users must submit a review when submitting a new apartment --- common/types/db-types.ts | 1 + .../components/utils/Footer/ContactModal.tsx | 34 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/common/types/db-types.ts b/common/types/db-types.ts index 20463657..cb395574 100644 --- a/common/types/db-types.ts +++ b/common/types/db-types.ts @@ -87,6 +87,7 @@ export type CantFindApartmentForm = { readonly address: string; readonly photos: readonly string[]; readonly userId?: string | null; + readonly review: string; }; export type CantFindApartmentFormWithId = CantFindApartmentForm & Id; diff --git a/frontend/src/components/utils/Footer/ContactModal.tsx b/frontend/src/components/utils/Footer/ContactModal.tsx index 04216936..f8762b09 100644 --- a/frontend/src/components/utils/Footer/ContactModal.tsx +++ b/frontend/src/components/utils/Footer/ContactModal.tsx @@ -112,18 +112,21 @@ interface CantFindApartmentFormData { name: string; address: string; localPhotos: File[]; + review: string; } const defaultApartmentForm: CantFindApartmentFormData = { name: '', address: '', localPhotos: [], + review: '', }; type apartmentFormAction = | { type: 'updateApartmentName'; name: string } | { type: 'updateApartmentAddress'; address: string } | { type: 'updatePhotos'; photos: File[] } + | { type: 'updateReview'; review: string } | { type: 'reset' }; const apartmentReducer = ( @@ -137,6 +140,8 @@ const apartmentReducer = ( return { ...state, address: action.address }; case 'updatePhotos': return { ...state, localPhotos: action.photos ? [...action.photos] : [] }; + case 'updateReview': + return { ...state, review: action.review }; case 'reset': return defaultApartmentForm; default: @@ -205,6 +210,7 @@ const ContactModal = ({ user }: Props) => { const [emptyNameError, setEmptyNameError] = useState(false); const [nameProfanityError, setNameProfanityError] = useState(false); const [addressProfanityError, setAddressProfanityError] = useState(false); + const [reviewProfanityError, setReviewProfanityError] = useState(false); // Question Modal const [questionForm, questionDispatch] = useReducer(questionReducer, defaultQuestionForm); @@ -250,6 +256,7 @@ const ContactModal = ({ user }: Props) => { setNameProfanityError(false); setAddressProfanityError(false); setEmptyNameError(false); + setReviewProfanityError(false); // Clear question errors setEmptyEmailError(false); @@ -262,6 +269,7 @@ const ContactModal = ({ user }: Props) => { name, address, localPhotos, + review, }: CantFindApartmentFormData): Promise => { const photos = await Promise.all(localPhotos.map(uploadFile)); return { @@ -270,6 +278,7 @@ const ContactModal = ({ user }: Props) => { address: address, photos, userId: user?.uid, + review: review, }; }; @@ -302,6 +311,10 @@ const ContactModal = ({ user }: Props) => { }); }; + const updateApartmentReview = (event: React.ChangeEvent) => { + apartmentDispatch({ type: 'updateReview', review: event.target.value }); + }; + const removePhoto = (index: number) => { const newPhotos = apartmentForm.localPhotos.filter((_, photoIndex) => index !== photoIndex); apartmentDispatch({ type: 'updatePhotos', photos: newPhotos }); @@ -358,6 +371,9 @@ const ContactModal = ({ user }: Props) => { includesProfanity(data.address) ? setAddressProfanityError(true) : setAddressProfanityError(false); + includesProfanity(data.review) + ? setReviewProfanityError(true) + : setReviewProfanityError(false); if (modalRef.current) { modalRef.current.scrollTop = 0; } @@ -533,11 +549,27 @@ const ContactModal = ({ user }: Props) => { addressProfanityError ? ' This contains profanity. Please edit it and try again.' : '' } onChange={updateApartmentAddress} - style={{ margin: '0', marginBottom: '30px' }} + style={{ margin: '0', marginBottom: '0' }} InputProps={{ style: { fontSize: '13px' }, }} /> + + Leave a Review (Optional) + + Date: Tue, 11 Nov 2025 16:50:53 -0500 Subject: [PATCH 3/3] Prompt to add apartment in search results --- frontend/src/pages/SearchResultsPage.tsx | 41 ++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/SearchResultsPage.tsx b/frontend/src/pages/SearchResultsPage.tsx index 4c14f447..4550f23f 100644 --- a/frontend/src/pages/SearchResultsPage.tsx +++ b/frontend/src/pages/SearchResultsPage.tsx @@ -4,15 +4,14 @@ import { useLocation } from 'react-router-dom'; import { get } from '../utils/call'; import { colors } from '../colors'; import { CardData } from '../App'; -import ApartmentCards from '../components/ApartmentCard/ApartmentCards'; import { useTitle } from '../utils'; -import { useSaveScrollPosition } from '../utils/saveScrollPosition'; import { defaultFilters } from '../components/Search/FilterSection'; import Autocomplete from '../components/Search/Autocomplete'; import SearchResultsPageApartmentCards from '../components/ApartmentCard/SearchResultsPageApartmentCards'; import SearchResultsMap from '../components/Search/SearchResultsMap'; import SortDropDown from '../components/Search/SortDropDown'; import { ApartmentWithId } from '../../../common/types/db-types'; +import { useModal } from '../components/utils/Footer/ContactModalContext'; const useStyles = makeStyles({ header: { @@ -94,6 +93,7 @@ const SearchResultsPage = ({ user, setUser }: Props): ReactElement => { }, [path.search]); const isMobile = useMediaQuery('(max-width:600px)'); + const { openModal } = useModal(); useTitle('Search Result'); @@ -226,6 +226,22 @@ const SearchResultsPage = ({ user, setUser }: Props): ReactElement => { sortMethod={sortBy} orderLowToHigh={sortLowToHigh} /> +
+ + Can't find your apartment? Tell us about it{' '} + + here + + ! + +
{ sortMethod={sortBy} orderLowToHigh={sortLowToHigh} /> +
+ + Can't find your apartment? Tell us about it{' '} + + here + + ! + +
)}