Skip to content

Commit

Permalink
All Referrals Page (#114)
Browse files Browse the repository at this point in the history
## Tracking Info

Resolves #73 

## Changes

<!-- What changes did you make? -->

- implement all referrals page

## Testing

<!-- How did you confirm your changes worked? -->

- verify all functionality works

## Confirmation of Change


![image](https://github.com/TritonSE/USHS-Housing-Portal/assets/24444266/c154acbc-f024-4eea-aebc-f4367891ebfa)

---------

Co-authored-by: Yashwanth Ravipati <[email protected]>
Co-authored-by: PoliteUnicorn <[email protected]>
  • Loading branch information
3 people authored Jun 13, 2024
1 parent c892194 commit 08ed025
Show file tree
Hide file tree
Showing 16 changed files with 597 additions and 38 deletions.
8 changes: 7 additions & 1 deletion backend/src/controllers/referral.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ObjectId } from "mongoose";

import { asyncHandler } from "./wrappers";

import { createReferral, deleteReferral, editReferral } from "@/services/referral";
import { createReferral, deleteReferral, editReferral, getAllReferrals } from "@/services/referral";

type CreateReferralRequestBody = {
renterCandidateId: string;
Expand Down Expand Up @@ -53,3 +53,9 @@ export const deleteReferralHandler: RequestHandler = asyncHandler(async (req, re
res.status(200).json(response);
}
});

export const getReferralsHandler: RequestHandler = asyncHandler(async (req, res, _) => {
const referrals = await getAllReferrals();

res.status(200).json(referrals);
});
14 changes: 14 additions & 0 deletions backend/src/controllers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { RequestHandler } from "express";

import { asyncHandler } from "./wrappers";

import { getReferralsForUser } from "@/services/referral";
import { createUser, demoteUser, elevateUser, getUserByID, getUsers } from "@/services/user";

export const getUsersHandler: RequestHandler = asyncHandler(async (_req, res, _next) => {
Expand Down Expand Up @@ -53,3 +54,16 @@ export const demoteUserHandler: RequestHandler = asyncHandler(async (req, res, _
res.status(200).json(demotedUser);
}
});

export const getUserReferrals: RequestHandler = asyncHandler(async (req, res, _) => {
const id = req.params.id;

const referrals = await getReferralsForUser(id);

if (referrals === null) {
res.status(404);
return;
}

res.status(200).json(referrals);
});
16 changes: 7 additions & 9 deletions backend/src/routes/referral.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import express from "express";

import {
createReferralHandler,
deleteReferralHandler,
editReferralHandler,
} from "@/controllers/referral";
import { requireUser } from "@/middleware/auth";
import * as ReferralController from "../controllers/referral";
import { requireUser } from "../middleware/auth";

const router = express.Router();

router.post("/", requireUser, createReferralHandler);
router.post("/", requireUser, ReferralController.createReferralHandler);

router.put("/:id", requireUser, editReferralHandler);
router.get("/", requireUser, ReferralController.getReferralsHandler);

router.delete("/:id", requireUser, deleteReferralHandler);
router.put("/:id", requireUser, ReferralController.editReferralHandler);

router.delete("/:id", requireUser, ReferralController.deleteReferralHandler);

export default router;
2 changes: 2 additions & 0 deletions backend/src/routes/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ router.put("/:id/elevate", requireHousingLocator, UserController.elevateUserHand

router.put("/:id/demote", requireHousingLocator, UserController.demoteUserHandler);

router.get("/:id/referrals", requireUser, UserController.getUserReferrals);

export default router;
37 changes: 35 additions & 2 deletions backend/src/services/referral.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import createHttpError from "http-errors";
import { ObjectId } from "mongoose";

import { ReferralModel } from "../models/referral";

import { sendEmail } from "./email";
import { getUserByID } from "./user";

import { ReferralModel } from "@/models/referral";

export async function getUnitReferrals(id: string) {
const referrals = await ReferralModel.find({ unit: id })
.populate("renterCandidate")
Expand Down Expand Up @@ -92,3 +93,35 @@ export async function deleteUnitReferrals(unitId: string) {
export async function deleteReferral(id: string) {
return await ReferralModel.deleteOne({ _id: id });
}

export async function getReferralsForUser(id: string) {
const user = await getUserByID(id);

if (!user) {
throw createHttpError(404, "User notfound.");
}

let query;
const { isHousingLocator } = user;

if (isHousingLocator) {
query = { assignedHousingLocator: id };
} else {
query = { assignedReferringStaff: id };
}

const referrals = await ReferralModel.find(query)
.populate("renterCandidate")
.populate("assignedHousingLocator")
.populate("assignedReferringStaff");

return referrals;
}

export async function getAllReferrals() {
const referrals = await ReferralModel.find({})
.populate("renterCandidate")
.populate("assignedHousingLocator")
.populate("assignedReferringStaff");
return referrals;
}
2 changes: 2 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
LandlordListingForm,
Login,
Profile,
Referrals,
RenterCandidatePage,
UnitDetails,
} from "@/pages";
Expand All @@ -36,6 +37,7 @@ function AppRouter() {
<Route path="/profile" element={<Profile />} />
<Route path="/unit/:id" element={<UnitDetails />} />
<Route path="/candidate/:id" element={<RenterCandidatePage />} />
<Route path="/referrals" element={<Referrals />} />
<Route path="*" element={<Navigate to="/" />} />
</>
)}
Expand Down
12 changes: 11 additions & 1 deletion frontend/src/api/referrals.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { APIResult, deleteRequest, handleAPIError, post, put } from "./requests";
import { APIResult, deleteRequest, get, handleAPIError, post, put } from "./requests";
import { Referral } from "./units";

export type CreateReferralRequest = {
Expand Down Expand Up @@ -46,3 +46,13 @@ export async function deleteReferral(id: string): Promise<APIResult<Referral>> {
return handleAPIError(error);
}
}

export async function getAllReferrals(): Promise<APIResult<Referral[]>> {
try {
const response = await get(`/referrals`);
const json = (await response.json()) as Referral[];
return { success: true, data: json };
} catch (error) {
return handleAPIError(error);
}
}
11 changes: 11 additions & 0 deletions frontend/src/api/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import { APIResult, get, handleAPIError, post, put } from "./requests";
import { Referral } from "./units";

export type User = {
_id: string;
Expand Down Expand Up @@ -63,3 +64,13 @@ export async function demoteUser(user: User): Promise<APIResult<User>> {
return handleAPIError(error);
}
}

export async function getReferralsForUser(user: User): Promise<APIResult<Referral[]>> {
try {
const response = await get(`/users/${user._id}/referrals`);
const json = (await response.json()) as Referral[];
return { success: true, data: json };
} catch (error) {
return handleAPIError(error);
}
}
6 changes: 3 additions & 3 deletions frontend/src/components/FilterDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const FiltersFirstRow = styled.div`
flex-wrap: wrap;
`;

const SearchBarInput = styled.input`
export const SearchBarInput = styled.input`
padding: 3px;
min-width: 16rem;
border: 0;
Expand All @@ -46,12 +46,12 @@ const SearchBarInput = styled.input`
}
`;

const SearchIcon = styled.img`
export const SearchIcon = styled.img`
height: 20px;
width: 20px;
`;

const SearchBarContainer = styled.div`
export const SearchBarContainer = styled.div`
display: flex;
flex-direction: row;
justify-content: flex-start;
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ const ButtonsWrapper = styled.div`
`;

type NavBarProps = {
page?: "Home" | "Profile";
page?: "Home" | "Profile" | "Referrals";
};

export function NavBar({ page }: NavBarProps) {
Expand Down Expand Up @@ -163,6 +163,9 @@ export function NavBar({ page }: NavBarProps) {
<NavItem to="/" $active={page === "Home"}>
Home
</NavItem>
<NavItem to="/referrals" $active={page === "Referrals"}>
Referrals
</NavItem>
<NavItem to="/profile" $active={page === "Profile"}>
Profile
</NavItem>
Expand Down
46 changes: 31 additions & 15 deletions frontend/src/components/ReferralPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,13 @@ type PopupProps = {
active: boolean;
onClose: () => void;
onSubmit: () => void;
newCandidateOnly?: boolean; // only add a new renter candidate
};

export const ReferralPopup = ({ active, onClose, onSubmit }: PopupProps) => {
export const ReferralPopup = ({ active, onClose, onSubmit, newCandidateOnly }: PopupProps) => {
const [popup, setPopup] = useState<boolean>(false);
const [addRC, setAddRC] = useState<boolean>(false);
console.log(newCandidateOnly);
const [addRC, setAddRC] = useState<boolean>(newCandidateOnly ?? false);
const [errorMsg, setErrorMsg] = useState<string>("");
const [currentRC, setCurrentRC] = useState<RenterCandidate>();
const [allRCs, setAllRCs] = useState<RenterCandidate[]>([]);
Expand Down Expand Up @@ -232,9 +234,13 @@ export const ReferralPopup = ({ active, onClose, onSubmit }: PopupProps) => {
createRenterCandidate(data as CreateRenterCandidateRequest)
.then((value) => {
if (value.success) {
handleCreateReferral(value.data._id);
reset();
setAddRC(false);
if (newCandidateOnly) {
onClose();
} else {
handleCreateReferral(value.data._id);
setAddRC(false);
}
setErrorMsg("");
} else {
if (value.error.includes("email")) {
Expand Down Expand Up @@ -267,7 +273,7 @@ export const ReferralPopup = ({ active, onClose, onSubmit }: PopupProps) => {
</XButton>
</XWrapper>
<Wrapper>
<h1>Add Referral</h1>
{newCandidateOnly ? <h1>Add New Renter Candidate</h1> : <h1>Add Referral</h1>}
{!addRC ? (
<ContentWrapper>
<div>Choose existing renter candidate:</div>
Expand Down Expand Up @@ -364,16 +370,26 @@ export const ReferralPopup = ({ active, onClose, onSubmit }: PopupProps) => {
/>
</InputSection>
<ButtonsWrapper>
<Button
onClick={() => {
setAddRC(false);
setErrorMsg("");
}}
kind="secondary"
>
Back
</Button>
<SubmitButton type="submit" value="Add Referral"></SubmitButton>
{newCandidateOnly ? (
<Button onClick={onClose} kind="secondary">
Cancel
</Button>
) : (
<Button
onClick={() => {
setAddRC(false);
setErrorMsg("");
}}
kind="secondary"
>
Back
</Button>
)}

<SubmitButton
type="submit"
value={newCandidateOnly ? "Add Client" : "Add Referral"}
></SubmitButton>
</ButtonsWrapper>
</FormWrapper>
<Error>{errorMsg}</Error>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/TablePagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ type ReferralTablePaginationProps = {
currPage: number;
setPageNumber: (newPageNumber: number) => void;
};

// TODO: Delete this file
export const TablePagination = (props: ReferralTablePaginationProps) => {
const [activePageNumber, setActivePageNumber] = useState(props.currPage);
const handleClick = (increase: boolean): void => {
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/components/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@ export const formatDate = (date: string): string => {
const dateObj = new Date(date);
return dateObj.toLocaleDateString("en-US");
};

export const formatPhoneNumber = (phoneNumber: string | undefined): string => {
if (!phoneNumber) return "";
const phone = phoneNumber.match(/\d+/g)?.join("");
return `(${phone?.substring(0, 3)}) ${phone?.substring(3, 6)}-${phone?.substring(6)}`;
};
Loading

0 comments on commit 08ed025

Please sign in to comment.