Skip to content

Commit 2cfc74a

Browse files
authored
Merge pull request #4010 from Northeastern-Electric-Racing/#4008-bom-misc-changes
#4008 bom improvements misc changes
2 parents 330c379 + 2bb0cc2 commit 2cfc74a

9 files changed

Lines changed: 420 additions & 621 deletions

File tree

src/frontend/src/pages/FinancePage/ReimbursementRequestDetailPage/ReimbursementProductsView.tsx

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { Box, Table, TableBody, TableCell, TableHead, TableRow, Typography } from '@mui/material';
1+
import { Box, Link, Table, TableBody, TableCell, TableHead, TableRow, Typography } from '@mui/material';
22
import { getUniqueWbsElementsWithProductsFromReimbursementRequest } from '../../../utils/reimbursement-request.utils';
33
import { ReimbursementRequest } from 'shared';
44
import { centsToDollar } from '../../../utils/pipes';
5+
import { routes } from '../../../utils/routes';
56

67
interface ReimbursementRequestProductsViewProps {
78
reimbursementRequest: ReimbursementRequest;
@@ -21,7 +22,6 @@ const ReimbursementProductsView: React.FC<ReimbursementRequestProductsViewProps>
2122
(product) => product.refundSources.length > 1
2223
);
2324

24-
// put all the refund source names in a set to avoid duplicate names
2525
const refundSourceNames: string[] = Array.from(
2626
new Set(
2727
reimbursementRequest.reimbursementProducts.flatMap((product) => product.refundSources.map((rs) => rs.indexCode.name))
@@ -58,16 +58,26 @@ const ReimbursementProductsView: React.FC<ReimbursementRequestProductsViewProps>
5858
return (
5959
<TableRow key={key}>
6060
<TableCell>
61-
<Box
62-
sx={{
63-
maxWidth: '64ch',
64-
overflowWrap: 'anywhere',
65-
whiteSpace: 'normal'
66-
}}
67-
>
68-
{uniqueWbsElementsWithProducts.get(key)?.map((product, index) => (
69-
<div key={index}>{product.name}</div>
70-
))}
61+
<Box sx={{ maxWidth: '64ch', overflowWrap: 'anywhere', whiteSpace: 'normal' }}>
62+
{uniqueWbsElementsWithProducts.get(key)?.map((product, index) => {
63+
const bomUrl = (() => {
64+
if (!product.materialId) return undefined;
65+
const reason = product.reimbursementProductReason;
66+
if (!('wbsNum' in reason)) return undefined;
67+
return `${routes.PROJECTS}/${reason.wbsNum.carNumber}.${reason.wbsNum.projectNumber}.${reason.wbsNum.workPackageNumber}/bom`;
68+
})();
69+
return (
70+
<div key={index}>
71+
{bomUrl ? (
72+
<Link href={bomUrl} underline="hover">
73+
{product.name}
74+
</Link>
75+
) : (
76+
product.name
77+
)}
78+
</div>
79+
);
80+
})}
7181
</Box>
7282
</TableCell>
7383
{!allKeysAreSame && <TableCell>{key}</TableCell>}

src/frontend/src/pages/FinancePage/ReimbursementRequestForm/ReimbursementProductTable.tsx

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { ReimbursementRequestFormInput } from './ReimbursementRequestForm';
3636
import { useTheme } from '@mui/system';
3737
import { useEffect, useState, useRef, useMemo } from 'react';
3838
import { useGetAllOtherProductReason } from '../../../hooks/finance.hooks';
39-
import { useGetMaterialsForWbsElement, useGetAssembliesForWbsElement } from '../../../hooks/bom.hooks';
39+
import { useGetMaterialsForWbsElement } from '../../../hooks/bom.hooks';
4040
import LoadingIndicator from '../../../components/LoadingIndicator';
4141
import ErrorPage from '../../ErrorPage';
4242
import { formatReasonName } from '../../../utils/reimbursement-request.utils';
@@ -174,13 +174,6 @@ const ReimbursementProductTable: React.FC<ReimbursementProductTableProps> = ({
174174
const [currentProject, setCurrentProject] = useState<ProjectPreview | null>(null);
175175
const [pendingMaterialIndices, setPendingMaterialIndices] = useState<Set<number>>(new Set());
176176

177-
const {
178-
data: assemblies,
179-
isLoading: assembliesLoading,
180-
isError: assembliesIsError,
181-
error: assembliesError
182-
} = useGetAssembliesForWbsElement(currentProject?.wbsNum || { carNumber: 0, projectNumber: 0, workPackageNumber: 0 });
183-
184177
const onCostBlurHandler = (value: number, index: number) => {
185178
setValue(`reimbursementProducts.${index}.cost`, parseFloat(value.toFixed(2)));
186179

@@ -337,9 +330,6 @@ const ReimbursementProductTable: React.FC<ReimbursementProductTableProps> = ({
337330
if (otherReasonIsError) {
338331
return <ErrorPage message={otherReasonError.message} />;
339332
}
340-
if (assembliesIsError) {
341-
return <ErrorPage message={assembliesError?.message || 'Failed to load assemblies'} />;
342-
}
343333

344334
return (
345335
<>
@@ -864,13 +854,13 @@ const ReimbursementProductTable: React.FC<ReimbursementProductTableProps> = ({
864854
</Table>
865855
</TableContainer>
866856

867-
{currentProject && !assembliesLoading && assemblies && (
857+
{currentProject && (
868858
<CreateMaterialModal
869859
open={showCreateMaterialModal}
870860
onHide={handleCloseCreateMaterial}
871861
wbsElement={currentProject}
872-
assemblies={assemblies}
873862
onSuccess={handleMaterialCreated}
863+
fromRRForm
874864
/>
875865
)}
876866
</>

src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/BOM/MaterialForm/CreateMaterialModal.tsx

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,33 @@
1-
import { Assembly, WbsElementPreview } from 'shared';
1+
import { WbsElementPreview } from 'shared';
22
import MaterialForm, { MaterialDataSubmission } from './MaterialForm';
3-
import LoadingIndicator from '../../../../../components/LoadingIndicator';
43
import { useToast } from '../../../../../hooks/toasts.hooks';
5-
import { useCreateMaterial } from '../../../../../hooks/bom.hooks';
4+
import { useCreateMaterial, useGetAssembliesForWbsElement } from '../../../../../hooks/bom.hooks';
65
import ErrorPage from '../../../../ErrorPage';
76

87
export interface CreateMaterialModalProps {
98
open: boolean;
109
onHide: () => void;
1110
wbsElement: WbsElementPreview;
12-
assemblies: Assembly[];
1311
onSuccess?: (materialName: string) => void;
12+
fromRRForm?: boolean;
1413
}
1514

16-
const CreateMaterialModal: React.FC<CreateMaterialModalProps> = ({ open, onHide, assemblies, wbsElement, onSuccess }) => {
17-
const { mutateAsync: createMaterial, isLoading, isError, error } = useCreateMaterial(wbsElement.wbsNum);
15+
const CreateMaterialModal: React.FC<CreateMaterialModalProps> = ({
16+
open,
17+
onHide,
18+
wbsElement,
19+
onSuccess,
20+
fromRRForm = false
21+
}) => {
22+
const { mutateAsync: createMaterial } = useCreateMaterial(wbsElement.wbsNum);
23+
const {
24+
data: assemblies,
25+
isError: assembliesIsError,
26+
error: assembliesError
27+
} = useGetAssembliesForWbsElement(wbsElement.wbsNum);
1828
const toast = useToast();
1929

20-
if (isLoading) return <LoadingIndicator />;
21-
if (isError) return <ErrorPage message={error?.message} />;
30+
if (assembliesIsError) return <ErrorPage message={assembliesError?.message} />;
2231

2332
const onSubmit = async (data: MaterialDataSubmission): Promise<void> => {
2433
try {
@@ -37,7 +46,16 @@ const CreateMaterialModal: React.FC<CreateMaterialModalProps> = ({ open, onHide,
3746
}
3847
};
3948

40-
return <MaterialForm submitText="Add" onSubmit={onSubmit} assemblies={assemblies} onHide={onHide} open={open} />;
49+
return (
50+
<MaterialForm
51+
submitText="Add"
52+
onSubmit={onSubmit}
53+
assemblies={assemblies}
54+
onHide={onHide}
55+
open={open}
56+
fromRRForm={fromRRForm}
57+
/>
58+
);
4159
};
4260

4361
export default CreateMaterialModal;

src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/BOM/MaterialForm/MaterialAdminWrapper.tsx

Lines changed: 0 additions & 74 deletions
This file was deleted.

src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/BOM/MaterialForm/MaterialForm.tsx

Lines changed: 39 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import React from 'react';
22
import { yupResolver } from '@hookform/resolvers/yup';
33
import { useForm } from 'react-hook-form';
4-
import { Assembly, MaterialStatus, RoleEnum } from 'shared';
4+
import { Assembly, MaterialStatus } from 'shared';
55
import * as yup from 'yup';
6-
import LoadingIndicator from '../../../../../components/LoadingIndicator';
76
import {
87
useCreateManufacturer,
98
useGetAllManufacturers,
@@ -12,10 +11,8 @@ import {
1211
} from '../../../../../hooks/bom.hooks';
1312
import ErrorPage from '../../../../ErrorPage';
1413
import { Decimal } from 'decimal.js';
15-
import { useCurrentUser } from '../../../../../hooks/users.hooks';
16-
import MaterialAdminWrapper from './MaterialAdminWrapper';
17-
import MaterialHeadWrapper from './MaterialHeadWrapper';
18-
import MaterialMemberWrapper from './MaterialMemberWrapper';
14+
import MaterialFormView from './MaterialFormView';
15+
import LoadingIndicator from '../../../../../components/LoadingIndicator';
1916

2017
const schema = yup.object().shape({
2118
name: yup.string().required('Enter a name!'),
@@ -72,10 +69,19 @@ export interface MaterialFormProps {
7269
defaultValues?: MaterialFormInput;
7370
onHide: () => void;
7471
open: boolean;
75-
assemblies: Assembly[];
72+
assemblies?: Assembly[];
73+
fromRRForm?: boolean;
7674
}
7775

78-
const MaterialForm: React.FC<MaterialFormProps> = ({ submitText, assemblies, onSubmit, defaultValues, onHide, open }) => {
76+
const MaterialForm: React.FC<MaterialFormProps> = ({
77+
submitText,
78+
assemblies,
79+
onSubmit,
80+
defaultValues,
81+
onHide,
82+
open,
83+
fromRRForm = false
84+
}) => {
7985
const {
8086
handleSubmit,
8187
control,
@@ -85,10 +91,10 @@ const MaterialForm: React.FC<MaterialFormProps> = ({ submitText, assemblies, onS
8591
} = useForm<MaterialFormInput>({
8692
defaultValues: {
8793
name: defaultValues?.name ?? '',
88-
status: defaultValues?.status ?? MaterialStatus.NotReadyToOrder,
94+
status: defaultValues?.status ?? (fromRRForm ? MaterialStatus.ReadyToOrder : MaterialStatus.NotReadyToOrder),
8995
materialTypeName: defaultValues?.materialTypeName ?? '',
9096
manufacturerPartNumber: defaultValues?.manufacturerPartNumber ?? '',
91-
quantity: defaultValues?.quantity ?? 0,
97+
quantity: defaultValues?.quantity ?? 1,
9298
manufacturerName: defaultValues?.manufacturerName ?? '',
9399
pdmFileName: defaultValues?.pdmFileName,
94100
price: defaultValues?.price ?? 0,
@@ -101,39 +107,19 @@ const MaterialForm: React.FC<MaterialFormProps> = ({ submitText, assemblies, onS
101107
resolver: yupResolver(schema)
102108
});
103109

104-
const user = useCurrentUser();
105-
106110
const { mutateAsync: createManufacturer, isLoading: isLoadingCreateManufacturer } = useCreateManufacturer();
107111

108-
const {
109-
data: materialTypes,
110-
isLoading: isLoadingMaterialTypes,
111-
isError: materialTypesIsError,
112-
error: materialTypesError
113-
} = useGetAllMaterialTypes();
112+
const { data: materialTypes, isError: materialTypesIsError, error: materialTypesError } = useGetAllMaterialTypes();
114113

115-
const { data: units, isLoading: isLoadingUnits, isError: unitsIsError, error: unitsError } = useGetAllUnits();
114+
const { data: units, isError: unitsIsError, error: unitsError } = useGetAllUnits();
116115

117-
const {
118-
data: manufactuers,
119-
isLoading: isLoadingManufactuers,
120-
isError: manufacturersIsError,
121-
error: manufacturersError
122-
} = useGetAllManufacturers();
116+
const { data: manufactuers, isError: manufacturersIsError, error: manufacturersError } = useGetAllManufacturers();
123117

124118
if (materialTypesIsError) return <ErrorPage message={materialTypesError.message} />;
125119
if (unitsIsError) return <ErrorPage message={unitsError.message} />;
126120
if (manufacturersIsError) return <ErrorPage message={manufacturersError.message} />;
127121

128-
if (
129-
isLoadingManufactuers ||
130-
isLoadingMaterialTypes ||
131-
isLoadingUnits ||
132-
!materialTypes ||
133-
!units ||
134-
!manufactuers ||
135-
isLoadingCreateManufacturer
136-
) {
122+
if (isLoadingCreateManufacturer) {
137123
return <LoadingIndicator />;
138124
}
139125

@@ -158,30 +144,25 @@ const MaterialForm: React.FC<MaterialFormProps> = ({ submitText, assemblies, onS
158144
}
159145
};
160146

161-
const sharedProps = {
162-
assemblies,
163-
allManufacturers: manufactuers,
164-
allMaterialTypes: materialTypes,
165-
allUnits: units,
166-
onSubmit: onSubmitWrapper,
167-
handleSubmit,
168-
submitText,
169-
onHide,
170-
control,
171-
errors,
172-
open,
173-
watch,
174-
createManufacturer: createManufacturerWrapper,
175-
setValue
176-
};
177-
178-
if (user.role === RoleEnum.APP_ADMIN || user.role === RoleEnum.ADMIN) {
179-
return <MaterialAdminWrapper {...sharedProps} />;
180-
}
181-
if (user.role === RoleEnum.HEAD || user.role === RoleEnum.LEADERSHIP) {
182-
return <MaterialHeadWrapper {...sharedProps} />;
183-
}
184-
return <MaterialMemberWrapper {...sharedProps} />;
147+
return (
148+
<MaterialFormView
149+
assemblies={assemblies}
150+
allManufacturers={manufactuers}
151+
allMaterialTypes={materialTypes}
152+
allUnits={units}
153+
onSubmit={onSubmitWrapper}
154+
handleSubmit={handleSubmit}
155+
submitText={submitText}
156+
onHide={onHide}
157+
control={control}
158+
errors={errors}
159+
open={open}
160+
watch={watch}
161+
createManufacturer={createManufacturerWrapper}
162+
setValue={setValue}
163+
fromRRForm={fromRRForm}
164+
/>
165+
);
185166
};
186167

187168
export default MaterialForm;

0 commit comments

Comments
 (0)