diff --git a/backend/src/controllers/units.ts b/backend/src/controllers/units.ts index 56cd12d..b7f9d8a 100644 --- a/backend/src/controllers/units.ts +++ b/backend/src/controllers/units.ts @@ -4,7 +4,7 @@ import createHttpError from "http-errors"; import { asyncHandler } from "./wrappers"; import { UnitModel } from "@/models/units"; -import { getUnitReferrals } from "@/services/referral"; +import { deleteUnitReferrals, getUnitReferrals } from "@/services/referral"; import { EditUnitBody, FilterParams, @@ -34,9 +34,13 @@ export const deleteUnitsHandler: RequestHandler = asyncHandler(async (req, res, const response = await deleteUnit(id); if (response === null) { res.status(400); - } else { - res.status(200).json(response); } + const referral = await deleteUnitReferrals(id); + if (referral === null) { + res.status(400); + } + + res.status(200).json(response); }); export const getUnitsHandler: RequestHandler = asyncHandler(async (req, res, _) => { diff --git a/backend/src/services/referral.ts b/backend/src/services/referral.ts index b90a744..d7820d0 100644 --- a/backend/src/services/referral.ts +++ b/backend/src/services/referral.ts @@ -85,6 +85,10 @@ export async function editReferral( return referral; } +export async function deleteUnitReferrals(unitId: string) { + return await ReferralModel.deleteMany({ unit: unitId }); +} + export async function deleteReferral(id: string) { return await ReferralModel.deleteOne({ _id: id }); } diff --git a/backend/src/validators/units.ts b/backend/src/validators/units.ts index c356e60..0f934cf 100644 --- a/backend/src/validators/units.ts +++ b/backend/src/validators/units.ts @@ -24,7 +24,9 @@ const createUnitSchema = [ .exists() .withMessage("is required") .isString() - .withMessage("must be a string"), + .withMessage("must be a string") + .notEmpty() + .withMessage("cannot be empty"), body("streetAddress") .exists() .withMessage("is required") diff --git a/frontend/public/plus_sign.svg b/frontend/public/plus_sign.svg index 09102b7..e92579c 100644 --- a/frontend/public/plus_sign.svg +++ b/frontend/public/plus_sign.svg @@ -1,3 +1,3 @@ - - - + + + \ No newline at end of file diff --git a/frontend/src/components/FilterDropdown.tsx b/frontend/src/components/FilterDropdown.tsx index b3c9f88..8bcf259 100644 --- a/frontend/src/components/FilterDropdown.tsx +++ b/frontend/src/components/FilterDropdown.tsx @@ -1,7 +1,11 @@ import { useContext } from "react"; +import { useNavigate } from "react-router-dom"; import styled from "styled-components"; +import { Button } from "./Button"; + import { SortDropDownComp } from "@/components/SortDropDown"; +import { DataContext } from "@/contexts/DataContext"; import { FiltersContext } from "@/pages/Home"; const AllFiltersContainer = styled.div` @@ -17,7 +21,7 @@ const FiltersFirstRow = styled.div` flex-direction: row; justify-content: flex-start; align-items: center; - gap: 28px; + gap: 33px; flex-wrap: wrap; `; @@ -59,6 +63,20 @@ const SearchBarContainer = styled.div` box-shadow: 1px 1px 2px 0px rgba(188, 186, 183, 0.4); `; +const AddListings = styled(Button)` + height: 44px; + display: flex; + flex-direction: row; + align-items: center; + gap: 6px; + font-size: 16px; + font-style: normal; + font-weight: 500; + line-height: 150%; + letter-spacing: 0.32px; + padding: 8px 20px; +`; + export type FilterDropdownProps = { searchText: string; sortIndex: number; @@ -66,6 +84,8 @@ export type FilterDropdownProps = { export const FilterDropdown = (props: FilterDropdownProps) => { const { filters, setFilters } = useContext(FiltersContext); + const navigate = useNavigate(); + const dataContext = useContext(DataContext); return ( @@ -80,6 +100,17 @@ export const FilterDropdown = (props: FilterDropdownProps) => { /> + {dataContext.currentUser?.isHousingLocator && ( + { + navigate("/new-listing"); + }} + > + + Listing + + )} { }} initialSelection={referral.assignedHousingLocator} options={allReferringStaff} + isTableDropdown={true} /> ); } @@ -215,6 +216,7 @@ export const ReferralTable = (props: ReferralTableProps) => { }} initialSelection={assignedReferringStaff} options={allReferringStaff} + isTableDropdown={true} />, HLSection(referral), { - const navigate = useNavigate(); - - const dataContext = useContext(DataContext); - return ( <> @@ -69,16 +41,6 @@ export const UnitCardGrid = ({ ))} {units.length === 0 && No matching units found} - {dataContext.currentUser?.isHousingLocator && ( - { - navigate("/new-listing"); - }} - > - add -
Listings
-
- )} ); }; diff --git a/frontend/src/components/UserDropdown.tsx b/frontend/src/components/UserDropdown.tsx index d916a7b..cfd8b9d 100644 --- a/frontend/src/components/UserDropdown.tsx +++ b/frontend/src/components/UserDropdown.tsx @@ -10,9 +10,9 @@ const SearchContainer = styled.div` position: relative; `; -const Icon = styled.img` +const Icon = styled.img<{ isTableDropdown?: boolean }>` position: absolute; - top: 10px; + top: ${(props) => (props.isTableDropdown ? "12px" : "10px")}; right: 10px; `; @@ -88,6 +88,7 @@ type SelectProps = { onSelect: (value: Option) => void; //callback function for parent, sends current selected user reset?: boolean; isRCDropdown?: boolean; + isTableDropdown?: boolean; }; export function UserDropdown({ @@ -98,6 +99,7 @@ export function UserDropdown({ onSelect, reset, isRCDropdown, + isTableDropdown, }: SelectProps) { const [openMenu, setOpenMenu] = useState(false); const [searchValue, setSearchValue] = useState(""); //current text value in select input box @@ -222,7 +224,11 @@ export function UserDropdown({ )} - + {isTableDropdown ? ( + + ) : ( + + )} ); } diff --git a/frontend/src/pages/RenterCandidatePage.tsx b/frontend/src/pages/RenterCandidatePage.tsx index bc53177..a4deff6 100644 --- a/frontend/src/pages/RenterCandidatePage.tsx +++ b/frontend/src/pages/RenterCandidatePage.tsx @@ -387,6 +387,7 @@ export function RenterCandidatePage() { }, }); }} + isTableDropdown={true} /> ); } @@ -657,6 +658,7 @@ export function RenterCandidatePage() { }, }); }} + isTableDropdown={true} />, HLSection(referral), diff --git a/frontend/src/pages/UnitDetails.tsx b/frontend/src/pages/UnitDetails.tsx index 6a17c6a..d5820f1 100644 --- a/frontend/src/pages/UnitDetails.tsx +++ b/frontend/src/pages/UnitDetails.tsx @@ -46,7 +46,7 @@ const Column = styled.div` flex-direction: column; background-color: #fbf7f3; justify-content: evenly-spaced; - gap: 16px; + gap: 8px; `; const HLActions = styled(Column)` @@ -59,7 +59,7 @@ const DetailsRow = styled(Row)` const SectionColumn = styled(Column)` width: 50%; - gap: 25px; + gap: 10px; `; const MainColumn = styled.div` @@ -69,7 +69,7 @@ const MainColumn = styled.div` `; const DetailsColumn = styled(MainColumn)` - margin: 32px 96px; + margin: 32px 150px; gap: 40px; `; @@ -90,7 +90,6 @@ const Header = styled.div` font-family: "Neutraface Text"; line-height: 150%; line-spacing: 0.64px; - margin-top: 32px; `; const Text = styled.div` @@ -101,13 +100,8 @@ const Text = styled.div` letter-spacing: 0.4px; `; -const List = styled.ul` - margin-top: 0; - margin-bottom: 0; - padding: 0, 0, 0, 10%; -`; - const StrongText = styled(Text)` + margin-top: 15px; font-weight: 600; line-height: 30px; letter-spacing: 0.4px; @@ -116,17 +110,23 @@ const StrongText = styled(Text)` const ListText = styled.li` font-family: "Montserrat"; font-weight: 400; - font-size: 20px; + font-size: 18px; line-height: 150% - letter-spacing: 0.4px; - margin-left: 6%; + letter-spacing: 0.32px; + margin-left: 3%; flex-wrap: wrap; margin-right: 10px; `; -const Address = styled(Header)` +const Address = styled.a` + font-size: 32px; + font-weight: 700; + font-family: "Neutraface Text"; + line-height: 150%; + line-spacing: 0.64px; padding: 0; margin: 0 0 5px 0; + color: black; `; const Availability = styled(Header)` @@ -333,6 +333,11 @@ const CarouselVideo = styled.video` padding: 0px 7.5px; `; +const SectionBreak = styled.hr` + background-color: #cdcaca; + height: 1px; + border: none; +`; type UnitDetailsLocationState = { filters: FilterParams; prevPage: string }; export function UnitDetails() { @@ -532,11 +537,15 @@ export function UnitDetails() { {rule} )); + const phone = unit.landlordPhone.match(/\d+/g)?.join(""); + const HousingLocatorComponent = () => { return ( Landlord: {unit.landlordFirstName + " " + unit.landlordLastName} - {unit.landlordPhone} + {`(${phone?.substring(0, 3)}) ${phone?.substring(3, 6)}-${phone?.substring( + 6, + )}`} {unit.landlordEmail} ); @@ -658,7 +667,12 @@ export function UnitDetails() { ${unit.monthlyRent}/month -
{unit.listingAddress}
+
+ {unit.listingAddress} +
{currentUser?.isHousingLocator && ( @@ -701,21 +715,17 @@ export function UnitDetails() { Security Deposit: - - ${unit.securityDeposit} - + ${unit.securityDeposit} Payment/Renting Criteria: {rentingCriteria} Application Fee: - - ${unit.applicationFeeCost} - + ${unit.applicationFeeCost} - +
Housing Specifications
@@ -732,7 +742,7 @@ export function UnitDetails() { {utilities} Housing Authority: {unit.housingAuthority} - Additional Comments from Landlord: + Comments from Landlord: {unit.landlordComments} @@ -748,6 +758,7 @@ export function UnitDetails() { {unit.approved && ( <> +
Additional Information
@@ -765,12 +776,14 @@ export function UnitDetails() {
+ {" "} )} {!unit.approved && ( <> + {