This commit is contained in:
Zeeshaun
2026-03-17 11:09:46 -05:00
parent bd1a9744ad
commit 6e7edcfe1b
332 changed files with 64174 additions and 0 deletions
@@ -0,0 +1,70 @@
import React, { useEffect } from "react";
import { connect } from "react-redux";
import { getAllRepoCompanies, postRepoCompany, putRepoCompany } from "../../actions/RepoCompanyActions";
import NotificationBar from "../../components/notification-bar/NotificationBar";
import { IRepoCompany } from "../../reducers/RepoCompanyReducer";
import AsyncState, { mapAsyncStateToNotificationType } from "../../shared/enumerations/AsyncState";
import IAsyncStateContainer from "../../shared/types/IAsyncStateContainer";
import { IAppState } from "../../store/Store";
import AdminRepoCompaniesTable from "./admin-repo-companies-table/AdminRepoCompaniesTable";
interface IPropsFromState {
repoCompanies: IAsyncStateContainer<IRepoCompany[]>;
}
const mapStateToProps = (state: IAppState): IPropsFromState => {
return {
repoCompanies: state.repoCompanyState.repoCompanies,
};
};
interface IPropsFromDispatch {
loadRepoCompanies: () => any;
putRepoCompany: (repoCompany: IRepoCompany) => any;
saveRepoCompany: (repoCompany: IRepoCompany) => any;
}
const mapDispatchToProps: IPropsFromDispatch = {
loadRepoCompanies: getAllRepoCompanies,
putRepoCompany: putRepoCompany,
saveRepoCompany: postRepoCompany
};
type Props = IPropsFromState & IPropsFromDispatch;
const AdminRepoCompanies: React.FC<Props> = (props) => {
useEffect(() => {
if (props.repoCompanies.state === AsyncState.Inactive) {
props.loadRepoCompanies();
}
});
const getNotificationBarType = () => {
return mapAsyncStateToNotificationType(props.repoCompanies.state);
};
return (
<div className="container-fluid main-panel" data-test="vehicle-floor-pricing-parameters">
{ !props.repoCompanies.data
?
<NotificationBar
type={getNotificationBarType()}
text={props.repoCompanies.state}
data-test="admin-repo-companies-notification-bar"
/>
:
<AdminRepoCompaniesTable
repoCompanies={props.repoCompanies.data}
putRepoCompany={props.putRepoCompany}
saveRepoCompany={props.saveRepoCompany}
data-test="admin-auction-houses-table"
/>
}
</div>
);
};
export const _AdminAuctionHouses = AdminRepoCompanies;
export default connect<IPropsFromState, IPropsFromDispatch, {}, IAppState>(mapStateToProps, mapDispatchToProps)(AdminRepoCompanies);
@@ -0,0 +1,7 @@
.admin-repo-companies-table {
overflow-x: auto;
}
.admin-repo-companies-table th {
min-width: 7.5em;
}
@@ -0,0 +1,51 @@
import React from "react";
import { IRepoCompany } from "../../../reducers/RepoCompanyReducer";
import AdminRepoCompanyCreation from "./admin-repo-company-creation/AdminRepoCompanyCreation";
import AdminRepoCompanyRow from "./admin-repo-company-row/AdminRepoCompanyRow";
import "./AdminRepoCompaniesTable.css";
interface IAdminRepoCompaniesTableProps {
repoCompanies: IRepoCompany[];
putRepoCompany: (repoCompany: IRepoCompany) => any;
saveRepoCompany: (repoCompany: IRepoCompany) => any;
}
const AdminRepoCompaniesTable: React.FC<IAdminRepoCompaniesTableProps> = (props) => {
return (
<table className="admin-repo-companies-table table table-striped">
<thead className="thead-light">
<tr>
<th scope="col">Name</th>
<th scope="col">ReferenceID</th>
<th scope="col">Email</th>
<th scope="col">Address #1</th>
<th scope="col">Address #2</th>
<th scope="col">City</th>
<th scope="col">State</th>
<th scope="col">ZIP</th>
<th scope="col">Country</th>
<th scope="col">Phone</th>
<th scope="col">Fax</th>
<th scope="col">Active</th>
<th className="button-actions-column" scope="col">Actions</th>
</tr>
</thead>
<tbody>
{props.repoCompanies.map((repoCompany) =>
<AdminRepoCompanyRow
key={repoCompany.id}
repoCompany={repoCompany}
putRepoCompany={props.putRepoCompany}
data-test="admin-repo-company-table-row"
/>
)}
</tbody>
<tbody>
<AdminRepoCompanyCreation saveRepoCompany={props.saveRepoCompany} />
</tbody>
</table>
);
};
export default AdminRepoCompaniesTable;
@@ -0,0 +1,3 @@
.admin-repo-company-creation-row {
background-color: transparent !important;
}
@@ -0,0 +1,61 @@
import { shallow } from "enzyme";
import React from "react";
import { IRepoCompany } from "../../../../reducers/RepoCompanyReducer";
import AdminRepoCompanyCreation from "./AdminRepoCompanyCreation";
describe("AdminRepoCompanyCreation Component", () => {
it("Updates & Calls Save Method", () => {
let savedRepoCompany: IRepoCompany | undefined;
// Arrange
const wrapper = shallow(
<AdminRepoCompanyCreation
saveRepoCompany={(x) => savedRepoCompany = x}
/>
);
const nameField = wrapper.find(`[data-test='name-field']`);
const referenceidField = wrapper.find(`[data-test='referenceid-field']`);
const emailField = wrapper.find(`[data-test='email-field']`);
const addr1Field = wrapper.find(`[data-test='addr-1-field']`);
const addr2Field = wrapper.find(`[data-test='addr-2-field']`);
const cityField = wrapper.find(`[data-test='city-field']`);
const stateField = wrapper.find(`[data-test='state-field']`);
const zipField = wrapper.find(`[data-test='zip-field']`);
const countryField = wrapper.find(`[data-test='country-field']`);
const phoneField = wrapper.find(`[data-test='phone-field']`);
const faxField = wrapper.find(`[data-test='fax-field']`);
// Act
nameField.simulate("change", "ABC Co.");
referenceidField.simulate("change", 2);
emailField.simulate("change", "[email protected]");
addr1Field.simulate("change", "1234 Main St.");
addr2Field.simulate("change", "#414");
cityField.simulate("change", "MKE");
stateField.simulate("change", "WI");
zipField.simulate("change", "53202");
countryField.simulate("change", "USA");
phoneField.simulate("change", "555-123-4567");
faxField.simulate("change", "555-111-2222");
const createButton = wrapper.find(`[data-test='create-btn']`);
createButton.simulate("click");
// Assert
expect(savedRepoCompany).not.toBe(undefined);
expect(savedRepoCompany!.referenceId).toBe(2);
expect(savedRepoCompany!.name).toBe("ABC Co.");
expect(savedRepoCompany!.email).toBe("[email protected]");
expect(savedRepoCompany!.address_Line_1).toBe("1234 Main St.");
expect(savedRepoCompany!.address_Line_2).toBe("#414");
expect(savedRepoCompany!.city).toBe("MKE");
expect(savedRepoCompany!.state).toBe("WI");
expect(savedRepoCompany!.zip).toBe("53202");
expect(savedRepoCompany!.country).toBe("USA");
expect(savedRepoCompany!.phone).toBe("555-123-4567");
expect(savedRepoCompany!.fax).toBe("555-111-2222");
});
});
@@ -0,0 +1,169 @@
import React from "react";
import FormInput, { FormInputType } from "../../../../components/form-input/FormInput";
import { IRepoCompany } from "../../../../reducers/RepoCompanyReducer";
import "./AdminRepoCompanyCreation.css";
interface IAdminRepoCompanyCreationProps {
saveRepoCompany: (repoCompany: IRepoCompany) => any;
}
interface IAdminRepoCompanyCreationState {
newRepoCompany: IRepoCompany;
}
class AdminRepoCompanyCreation extends React.Component<IAdminRepoCompanyCreationProps, IAdminRepoCompanyCreationState> {
constructor(props: IAdminRepoCompanyCreationProps) {
super(props);
this.state = {
newRepoCompany: {
name: ""
} as IRepoCompany
};
this.saveRepoCompany = this.saveRepoCompany.bind(this);
}
applyChange(updater: (repoCompany: IRepoCompany) => any) {
const copiedRepoCompany = {...this.state.newRepoCompany};
updater(copiedRepoCompany);
this.setState({
newRepoCompany: copiedRepoCompany
});
}
isFormValid(): boolean {
return this.state.newRepoCompany.name.trim() !== "";
}
saveRepoCompany(): void {
if (this.isFormValid()) {
this.props.saveRepoCompany(this.state.newRepoCompany!);
}
}
render() {
return (
<tr className="admin-repo-company-creation-row">
<td>
<FormInput
type={FormInputType.Text}
placeholder="New Repo Company LLC"
value={this.state.newRepoCompany.name}
onChange={(value) => this.applyChange(repoCompany => repoCompany.name = value)}
data-test="name-field"
/>
</td>
<td>
<FormInput
placeholder="ReferenceId"
type={FormInputType.Number}
value={this.state.newRepoCompany.referenceId}
onChange={(value) => this.applyChange(repoCompany => repoCompany.referenceId = value)}
data-test="referenceid-field"
/>
</td>
<td>
<FormInput
type={FormInputType.Text}
placeholder="[email protected]"
value={this.state.newRepoCompany.email}
onChange={(value) => this.applyChange(repoCompany => repoCompany.email = value)}
data-test="email-field"
/>
</td>
<td>
<FormInput
type={FormInputType.Text}
placeholder="Address #1"
value={this.state.newRepoCompany.address_Line_1}
onChange={(value) => this.applyChange(repoCompany => repoCompany.address_Line_1 = value)}
data-test="addr-1-field"
/>
</td>
<td>
<FormInput
type={FormInputType.Text}
placeholder="Address #2"
value={this.state.newRepoCompany.address_Line_2}
onChange={(value) => this.applyChange(repoCompany => repoCompany.address_Line_2 = value)}
data-test="addr-2-field"
/>
</td>
<td>
<FormInput
type={FormInputType.Text}
placeholder="City"
value={this.state.newRepoCompany.city}
onChange={(value) => this.applyChange(repoCompany => repoCompany.city = value)}
data-test="city-field"
/>
</td>
<td>
<FormInput
type={FormInputType.Text}
placeholder="State"
value={this.state.newRepoCompany.state}
onChange={(value) => this.applyChange(repoCompany => repoCompany.state = value)}
data-test="state-field"
/>
</td>
<td>
<FormInput
type={FormInputType.Text}
placeholder="ZIP"
value={this.state.newRepoCompany.zip}
onChange={(value) => this.applyChange(repoCompany => repoCompany.zip = value)}
data-test="zip-field"
/>
</td>
<td>
<FormInput
type={FormInputType.Text}
placeholder="Country"
value={this.state.newRepoCompany.country}
onChange={(value) => this.applyChange(repoCompany => repoCompany.country = value)}
data-test="country-field"
/>
</td>
<td>
<FormInput
type={FormInputType.Text}
placeholder="Phone"
value={this.state.newRepoCompany.phone}
onChange={(value) => this.applyChange(repoCompany => repoCompany.phone = value)}
data-test="phone-field"
/>
</td>
<td>
<FormInput
type={FormInputType.Text}
placeholder="Fax"
value={this.state.newRepoCompany.fax}
onChange={(value) => this.applyChange(repoCompany => repoCompany.fax = value)}
data-test="fax-field"
/>
</td>
<td>
<p>Yes</p>
</td>
<td>
<button
type="button"
className="btn btn-success"
disabled={!this.isFormValid()}
onClick={this.saveRepoCompany}
data-test="create-btn"
>
<i className="fa fa-plus" aria-hidden="true"/>
&nbsp;
Create
</button>
</td>
</tr>
);
}
}
export default AdminRepoCompanyCreation;
@@ -0,0 +1,7 @@
.admin-repo-company-row-form button {
margin-right: 0.5em;
}
.disabled-repo-company-row p {
opacity: 0.5;
}
@@ -0,0 +1,110 @@
import { shallow, ShallowWrapper } from "enzyme";
import moment from "moment";
import React from "react";
import { IRepoCompany } from "../../../../reducers/RepoCompanyReducer";
import AdminRepoCompanyRow from "./AdminRepoCompanyRow";
describe("AdminRepoCompanyCreation Component", () => {
let wrapper: ShallowWrapper;
beforeEach(() => {
wrapper = shallow(
<AdminRepoCompanyRow
repoCompany={{
id: 1,
name: "ABC Co.",
referenceId: 2,
email: "[email protected]",
address_Line_1: "1234 Main St.",
address_Line_2: "#414",
city: "MKE",
state: "WI",
zip: "53202",
country: "USA",
phone: "555-123-4567",
fax: "555-987-6543",
disabledDate: moment()
}}
putRepoCompany={(_) => {}}
/>
);
});
it("Renders Only Labels When Not Edited", () => {
const labelRow = wrapper.find(`[data-test='label-version']`);
expect(labelRow.length).toBe(1);
const inputRow = wrapper.find(`[data-test='input-version']`);
expect(inputRow.length).toBe(0);
});
it("Renders Only Inputs When Edited", () => {
const editRowBtn = wrapper.find(`[data-test='edit-row-btn']`);
editRowBtn.simulate("click");
const labelRow = wrapper.find(`[data-test='label-version']`);
expect(labelRow.length).toBe(0);
const inputRow = wrapper.find(`[data-test='input-version']`);
expect(inputRow.length).toBe(1);
});
it("Renders Fieids Correctly When Edited", () => {
// Arrange
const editRowBtn = wrapper.find(`[data-test='edit-row-btn']`);
editRowBtn.simulate("click");
const nameField = wrapper.find(`[data-test='name-field']`);
const referenceidField = wrapper.find(`[data-test='referenceid-field']`);
const emailField = wrapper.find(`[data-test='email-field']`);
const addr1Field = wrapper.find(`[data-test='addr-1-field']`);
const addr2Field = wrapper.find(`[data-test='addr-2-field']`);
const cityField = wrapper.find(`[data-test='city-field']`);
const stateField = wrapper.find(`[data-test='state-field']`);
const zipField = wrapper.find(`[data-test='zip-field']`);
const countryField = wrapper.find(`[data-test='country-field']`);
const phoneField = wrapper.find(`[data-test='phone-field']`);
const faxField = wrapper.find(`[data-test='fax-field']`);
const isActiveField = wrapper.find(`[data-test='is-active-field']`);
// Assert
expect(nameField.props().value).toBe("ABC Co.");
expect(referenceidField.props().value).toBe(2);
expect(emailField.props().value).toBe("[email protected]");
expect(addr1Field.props().value).toBe("1234 Main St.");
expect(addr2Field.props().value).toBe("#414");
expect(cityField.props().value).toBe("MKE");
expect(stateField.props().value).toBe("WI");
expect(zipField.props().value).toBe("53202");
expect(countryField.props().value).toBe("USA");
expect(phoneField.props().value).toBe("555-123-4567");
expect(faxField.props().value).toBe("555-987-6543");
expect(isActiveField.props().value).toBe(0);
});
it("Save Method Callback Triggered", () => {
// Arrange
let updatedRepoCompany: IRepoCompany | undefined;
wrapper.setProps({
putRepoCompany: (x: IRepoCompany) => updatedRepoCompany = x
});
const editRowBtn = wrapper.find(`[data-test='edit-row-btn']`);
editRowBtn.simulate("click");
const nameField = wrapper.find(`[data-test='name-field']`);
// Act
nameField.simulate("change", "New Company!");
const saveRowBtn = wrapper.find(`[data-test='save-row-btn']`);
saveRowBtn.simulate("click");
// Assert
expect(updatedRepoCompany).not.toBeUndefined();
expect(updatedRepoCompany!.name).toEqual("New Company!");
});
});
@@ -0,0 +1,280 @@
import moment from "moment";
import React from "react";
import FormInput, { FormInputType } from "../../../../components/form-input/FormInput";
import { IRepoCompany } from "../../../../reducers/RepoCompanyReducer";
import "./AdminRepoCompanyRow.css";
interface IRepoCompanyRowProps {
repoCompany: IRepoCompany;
putRepoCompany: (repoCompany: IRepoCompany) => any;
}
interface IRepoCompanyRowState {
editedRepoCompany?: IRepoCompany;
}
class AdminRepoCompanyRow extends React.Component<IRepoCompanyRowProps, IRepoCompanyRowState> {
constructor(props: IRepoCompanyRowProps) {
super(props);
this.state = {};
this.applyIsActiveChange = this.applyIsActiveChange.bind(this);
}
componentDidUpdate(prevProps: IRepoCompanyRowProps, prevState: IRepoCompanyRowState) {
if (prevState !== this.state) {
return;
}
if (prevProps.repoCompany !== this.props.repoCompany) {
this.setState({
editedRepoCompany: undefined
});
}
}
applyChange(updater: (repoCompany: IRepoCompany) => any) {
if (!this.state.editedRepoCompany) {
return;
}
const copiedRepoCompany = {...this.state.editedRepoCompany};
updater(copiedRepoCompany);
this.setState({
editedRepoCompany: copiedRepoCompany
});
}
applyIsActiveChange(value: string) {
const isActive = !!parseInt(value);
const disabledDate = isActive ? undefined : moment();
this.applyChange(repoCompany => repoCompany.disabledDate = disabledDate);
}
beginEditingRow() {
this.setState({
editedRepoCompany: {
...this.props.repoCompany
}
});
}
cancelEditingRow() {
this.setState({
editedRepoCompany: undefined
});
}
hasStringFieldChanged(fieldExtraction: (repoCompany: IRepoCompany) => string | null | undefined) {
const orig = fieldExtraction(this.props.repoCompany);
const edited = this.state.editedRepoCompany ? fieldExtraction(this.state.editedRepoCompany) : undefined;
return (orig || "") !== (edited || "");
}
isRepoCompanyAltered() {
if (!this.state.editedRepoCompany) {
return false;
}
return (
this.props.repoCompany.name !== this.state.editedRepoCompany.name ||
this.hasStringFieldChanged(repoCompany => repoCompany.email) ||
this.props.repoCompany.referenceId !== this.state.editedRepoCompany.referenceId ||
this.hasStringFieldChanged(repoCompany => repoCompany.address_Line_1) ||
this.hasStringFieldChanged(repoCompany => repoCompany.address_Line_2) ||
this.hasStringFieldChanged(repoCompany => repoCompany.city) ||
this.hasStringFieldChanged(repoCompany => repoCompany.state) ||
this.hasStringFieldChanged(repoCompany => repoCompany.zip) ||
this.hasStringFieldChanged(repoCompany => repoCompany.country) ||
this.hasStringFieldChanged(repoCompany => repoCompany.phone) ||
this.hasStringFieldChanged(repoCompany => repoCompany.fax) ||
!!this.props.repoCompany.disabledDate !== !!this.state.editedRepoCompany.disabledDate
);
}
isRowDisabled(): boolean {
return !!this.props.repoCompany.disabledDate;
}
render() {
if (this.state.editedRepoCompany) {
const areStringInputsDisabled = !!this.state.editedRepoCompany.disabledDate;
return (
<tr className="admin-repo-company-row-form" data-test="input-version">
<td>
<FormInput
placeholder="Name"
type={FormInputType.Text}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.name}
onChange={(value) => this.applyChange(repoCompany => repoCompany.name = value)}
data-test="name-field"
/>
</td>
<td>
<FormInput
placeholder="ReferenceId"
type={FormInputType.Number}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.referenceId}
onChange={(value) => this.applyChange(repoCompany => repoCompany.referenceId = value)}
data-test="referenceid-field"
/>
</td>
<td>
<FormInput
placeholder="Email"
type={FormInputType.Text}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.email}
onChange={(value) => this.applyChange(repoCompany => repoCompany.email = value)}
data-test="email-field"
/>
</td>
<td>
<FormInput
placeholder="Address #1"
type={FormInputType.Text}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.address_Line_1}
onChange={(value) => this.applyChange(repoCompany => repoCompany.address_Line_1 = value)}
data-test="addr-1-field"
/>
</td>
<td>
<FormInput
placeholder="Address #2"
type={FormInputType.Text}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.address_Line_2}
onChange={(value) => this.applyChange(repoCompany => repoCompany.address_Line_2 = value)}
data-test="addr-2-field"
/>
</td>
<td>
<FormInput
placeholder="City"
type={FormInputType.Text}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.city}
onChange={(value) => this.applyChange(repoCompany => repoCompany.city = value)}
data-test="city-field"
/>
</td>
<td>
<FormInput
placeholder="State"
type={FormInputType.Text}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.state}
onChange={(value) => this.applyChange(repoCompany => repoCompany.state = value)}
data-test="state-field"
/>
</td>
<td>
<FormInput
placeholder="ZIP"
type={FormInputType.Text}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.zip}
onChange={(value) => this.applyChange(repoCompany => repoCompany.zip = value)}
data-test="zip-field"
/>
</td>
<td>
<FormInput
placeholder="Country"
type={FormInputType.Text}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.country}
onChange={(value) => this.applyChange(repoCompany => repoCompany.country = value)}
data-test="country-field"
/>
</td>
<td>
<FormInput
placeholder="Phone"
type={FormInputType.Text}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.phone}
onChange={(value) => this.applyChange(repoCompany => repoCompany.phone = value)}
data-test="phone-field"
/>
</td>
<td>
<FormInput
placeholder="Fax"
type={FormInputType.Text}
disabled={areStringInputsDisabled}
value={this.state.editedRepoCompany.fax}
onChange={(value) => this.applyChange(repoCompany => repoCompany.fax = value)}
data-test="fax-field"
/>
</td>
<td>
<FormInput
type={FormInputType.Selection}
value={!this.state.editedRepoCompany.disabledDate ? 1 : 0}
onChange={this.applyIsActiveChange}
data-test="is-active-field"
options={[
{ value: 1, display: "Yes" },
{ value: 0, display: "No" }
]}
/>
</td>
<td className="button-actions-column">
<button
type="button"
className="btn btn-success"
disabled={!this.isRepoCompanyAltered()}
onClick={() => this.props.putRepoCompany(this.state.editedRepoCompany!)}
data-test="save-row-btn"
>
<i className="fa fa-floppy-o" aria-hidden="true"/>
</button>
<button
type="button"
className="btn btn-warning"
onClick={() => this.cancelEditingRow()}
data-test="cancel-row-btn"
>
<i className="fa fa-ban" aria-hidden="true"/>
</button>
</td>
</tr>
);
} else {
return (
<tr className={this.isRowDisabled() ? "disabled-repo-company-row" : ""} data-test="label-version">
<td><p>{this.props.repoCompany.name}</p></td>
<td>{this.props.repoCompany.referenceId || "-"}</td>
<td><p>{this.props.repoCompany.email}</p></td>
<td><p>{this.props.repoCompany.address_Line_1 || "-"}</p></td>
<td><p>{this.props.repoCompany.address_Line_2 || "-"}</p></td>
<td><p>{this.props.repoCompany.city || "-"}</p></td>
<td><p>{this.props.repoCompany.state || "-"}</p></td>
<td><p>{this.props.repoCompany.zip || "-"}</p></td>
<td><p>{this.props.repoCompany.country || "-"}</p></td>
<td><p>{this.props.repoCompany.phone || "-"}</p></td>
<td><p>{this.props.repoCompany.fax || "-"}</p></td>
<td><p>{!this.props.repoCompany.disabledDate ? "Yes" : "No"}</p></td>
<td className="button-actions-column">
<button
type="button"
className="btn btn-primary"
onClick={() => this.beginEditingRow()}
data-test="edit-row-btn"
>
<i className="fa fa-pencil" aria-hidden="true"/>
</button>
</td>
</tr>
);
}
}
}
export default AdminRepoCompanyRow;