Skip to content
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
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Box, Tooltip, IconButton } from '@mui/material';
import { useLocation, useHistory, useParams } from 'react-router-dom';
import { useState, useEffect } from 'react';
import { isGuest, ReimbursementRequest } from 'shared';
import { equalsWbsNumber, isGuest, ReimbursementRequest, validateWBS, WBSElementData } from 'shared';
import { ReimbursementProduct, ReimbursementStatusType } from 'shared';
import { undefinedPipe, fullNamePipe, centsToDollar, datePipe, dateUndefinedPipe } from '../../../utils/pipes';
import {
Expand All @@ -25,6 +25,7 @@ interface ReimbursementRequestInfoProps {
statuses?: ReimbursementStatusType[];
startDate?: Date | null;
endDate?: Date | null;
selectedProject?: { label: string; id: string };
onCloseSidePage: () => void;
}

Expand All @@ -37,6 +38,7 @@ const ReimbursementRequestInfo = ({
statuses,
startDate,
endDate,
selectedProject,
onCloseSidePage
}: ReimbursementRequestInfoProps) => {
const user = useCurrentUser();
Expand Down Expand Up @@ -71,6 +73,22 @@ const ReimbursementRequestInfo = ({
return false;
}

if (selectedProject) {
const filterWbsNum = validateWBS(selectedProject.id);

const matchesProject = request.reimbursementProducts.some((product) => {
const reason = product.reimbursementProductReason;
if ((reason as WBSElementData).wbsNum) {
return equalsWbsNumber(
{ ...(reason as WBSElementData).wbsNum, workPackageNumber: 0 },
{ ...filterWbsNum, workPackageNumber: 0 }
);
}
return false;
});
if (!matchesProject) return false;
}

return true;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface ReimbursementRequestTableProps {
statuses?: ReimbursementStatusType[];
startDate?: Date | null;
endDate?: Date | null;
selectedProject?: { label: string; id: string };
}

const ReimbursementRequestTable = ({
Expand All @@ -24,7 +25,8 @@ const ReimbursementRequestTable = ({
onCloseSidePage,
statuses,
startDate,
endDate
endDate,
selectedProject
}: ReimbursementRequestTableProps) => {
const defaultTab = '/my-requests';

Expand Down Expand Up @@ -68,6 +70,7 @@ const ReimbursementRequestTable = ({
statuses={statuses}
startDate={startDate}
endDate={endDate}
selectedProject={selectedProject}
onCloseSidePage={onCloseSidePage}
/>
</Box>
Expand Down
60 changes: 58 additions & 2 deletions src/frontend/src/pages/FinancePage/ReimbursmentRequests.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import { Box, Button, Menu, MenuItem, ListItemIcon, Typography, FormControlLabel, Checkbox } from '@mui/material';
import {
Box,
Button,
Menu,
MenuItem,
ListItemIcon,
Typography,
FormControlLabel,
Checkbox,
Autocomplete,
TextField
} from '@mui/material';
import { useState } from 'react';
import AttachMoneyIcon from '@mui/icons-material/AttachMoney';
import { NERButton } from '../../components/NERButton';
import ReceiptIcon from '@mui/icons-material/Receipt';
import WorkIcon from '@mui/icons-material/Work';
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
import { useCurrentUser } from '../../hooks/users.hooks';
import { isAdmin, isGuest, isHead, isLead, ReimbursementStatusType } from 'shared';
import { isAdmin, isGuest, isHead, isLead, ReimbursementStatusType, wbsPipe } from 'shared';
import FilterListIcon from '@mui/icons-material/FilterList';
import ReimbursementRequestTable from './ReimbursementRequestsSection';
import { useToast } from '../../hooks/toasts.hooks';
Expand All @@ -20,6 +31,8 @@ import { DatePicker } from '@mui/x-date-pickers';
import ReportRefundModal from './FinanceComponents/ReportRefundModal';
import GenerateReceiptsModal from './FinanceComponents/GenerateReceiptsModal';
import ErrorPage from '../ErrorPage';
import { useAllProjects } from '../../hooks/projects.hooks';
import LoadingIndicator from '../../components/LoadingIndicator';

const ReimbursementRequests: React.FC = () => {
const allStatuses = Object.values(ReimbursementStatusType);
Expand Down Expand Up @@ -114,16 +127,24 @@ const ReimbursementRequests: React.FC = () => {
isError: allReimbursementRequestsIsError,
error: allReimbursementRequestsError
} = useAllReimbursementRequests();
const {
data: allProjects,
isLoading: allProjectsIsLoading,
isError: allProjectsIsError,
error: allProjectsError
} = useAllProjects();

const [anchorFilterEl, setAnchorFilterEl] = useState<null | HTMLElement>(null);
const [selectedStatuses, setSelectedStatuses] = useState<ReimbursementStatusType[]>([]);
const [startDate, setStartDate] = useState<null | Date>(null);
const [endDate, setEndDate] = useState<Date | null>(null);
const [selectedProjectFilter, setSelectedProjectFilter] = useState<{ label: string; id: string } | null>(null);

const clearData = () => {
setSelectedStatuses([]);
setStartDate(null);
setEndDate(null);
setSelectedProjectFilter(null);
};

const handleFilterMenuOpen = (e: React.MouseEvent<HTMLElement>) => setAnchorFilterEl(e.currentTarget);
Expand All @@ -135,6 +156,13 @@ const ReimbursementRequests: React.FC = () => {
if (assignedReimbursementRequestIsError) return <ErrorPage message={assignedReimbursementRequestError?.message} />;
if (createdReimbursementRequestIsError) return <ErrorPage message={createdReimbursementRequestError?.message} />;

const projectAutocompleteOptions = allProjects
? allProjects.map((proj) => ({
label: wbsPipe(proj.wbsNum) + ' - ' + proj.name,
id: wbsPipe(proj.wbsNum)
}))
: [];

const filterMenu = (
<Menu
open={Boolean(anchorFilterEl)}
Expand Down Expand Up @@ -189,6 +217,33 @@ const ReimbursementRequests: React.FC = () => {
</MenuItem>
);
})}
<Typography sx={{ fontWeight: 'bold', mt: 2, mb: 1 }}>Filter by Project</Typography>
<Box
sx={{
borderBottom: '2px solid white',
mb: 2
}}
/>
{allProjectsIsLoading ? (
<LoadingIndicator />
) : allProjectsIsError ? (
<Typography color="error" sx={{ mb: 1 }}>
Failed to load projects {allProjectsError?.message}
</Typography>
) : (
<Autocomplete
sx={{ flex: 1 }}
options={projectAutocompleteOptions}
value={selectedProjectFilter}
blurOnSelect={true}
id={'project-filter-autocomplete'}
size={'small'}
onChange={(_event, newValue) => {
setSelectedProjectFilter(newValue);
}}
renderInput={(params) => <TextField {...params} variant="outlined" placeholder="Select Project" fullWidth />}
/>
)}
<Typography sx={{ fontWeight: 'bold', mt: 2, mb: 1 }}>Filter by Date</Typography>
<Box
sx={{
Expand Down Expand Up @@ -271,6 +326,7 @@ const ReimbursementRequests: React.FC = () => {
statuses={selectedStatuses}
startDate={startDate}
endDate={endDate}
selectedProject={selectedProjectFilter ?? undefined}
onCloseSidePage={() => {
refetchCreatedReimbursementRequests();
refetchAllReimbursementRequests();
Expand Down
Loading