Skip to content

Commit

Permalink
Added manufacturer list and editing
Browse files Browse the repository at this point in the history
  • Loading branch information
davewalker5 committed Dec 3, 2023
1 parent 87ee0c7 commit fd02748
Show file tree
Hide file tree
Showing 16 changed files with 490 additions and 6 deletions.
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ To be implemented in a future release.
### Equipment Types

- To view a list of equipment types in the database, click on the "Equipment > Equipment Types" menu item
- A page listing the equpiment types in the database is displayed:
- A page listing the equipment types in the database is displayed:

<img src="diagrams/equipment-types-list.png" alt="Equipment Types List" width="600">

Expand All @@ -281,7 +281,17 @@ To be implemented in a future release.

### Manufacturers

To be implemented in a future release.
- To view a list of manufacturers in the database, click on the "Equipment > Manufacturers" menu item
- A page listing the manufacturers in the database is displayed:

<img src="diagrams/manufacturer-list.png" alt="Equipment Types List" width="600">

- Clicking on the trash can icon in a row will prompt for confirmation and then attempt to delete the manufacturer on the selected row
- Manufacturers that are currently "in use" (associated with an item of equpiment) cannot be deleted and attempting to delete them will result in an error message being displayed
- Clicking on the "Add" button opens the manufacturer editing page (see below) to add a new manufacturer
- Clicking on the edit icon in a row navigates to the manufacturer editing page for that manufacturer (see below)

<img src="diagrams/manufacturer-editor.png" alt="Equipment Type Editor" width="600">

#### The Retailers List

Expand Down
Binary file added diagrams/manufacturer-editor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added diagrams/manufacturer-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions src/music-catalogue-ui/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@ const defaultContext = {
// Current page
page: pages.artists,

// Artist, album, track and retailer context
// Music catalogue
artist: null,
album: null,
track: null,
genre: null,
retailer: null,

// Equipment registry
equipmentType: null,
manufacturer: null,

// Data retrieval/filering criteria
genre: null,
filter: "A",
isWishList: false,
};
Expand All @@ -43,6 +47,7 @@ const App = () => {
retailer = null,
genre = null,
equipmentType = null,
manufacturer = null,
filter = "A",
isWishList = false,
} = {}) => {
Expand All @@ -55,6 +60,7 @@ const App = () => {
retailer: typeof retailer != "undefined" ? retailer : null,
genre: typeof genre != "undefined" ? genre : null,
equipmentType: typeof equipmentType != "undefined" ? equipmentType : null,
manufacturer: typeof manufacturer != "undefined" ? manufacturer : null,
filter: typeof filter != "undefined" ? filter : "A",
isWishList: typeof isWishList != "undefined" ? isWishList : false,
};
Expand Down
12 changes: 12 additions & 0 deletions src/music-catalogue-ui/components/componentPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import ArtistEditor from "./artists/artistEditor";
import RetailerStatisticsReport from "./reports/retailerStatisticsReport";
import EquipmentTypeList from "./equipmentTypes/equipmentTypeList";
import EquipmentTypeEditor from "./equipmentTypes/equipmentTypeEditor";
import ManufacturerList from "./manufacturers/manufacturerList";
import ManufacturerEditor from "./manufacturers/manufacturerEditor";

/**
* Component using the current context to select and render the current page
Expand Down Expand Up @@ -129,6 +131,16 @@ const ComponentPicker = ({ context, navigate, logout }) => {
logout={logout}
/>
);
case pages.manufacturers:
return <ManufacturerList navigate={navigate} logout={logout} />;
case pages.manufacturerEditor:
return (
<ManufacturerEditor
manufacturer={context.manufacturer}
navigate={navigate}
logout={logout}
/>
);
case pages.export:
return <ExportCatalogue logout={logout} />;
case pages.artistStatisticsReport:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const EquipmentTypeEditor = ({ equipmentType, navigate, logout }) => {
);
}

// Go back to the artist list, which should reflect the updated details
// Go back to the equipment type list, which should reflect the updated details
navigate({
page: pages.equipmentTypes,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useCallback } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faTrashAlt } from "@fortawesome/free-solid-svg-icons";
import {
apiDeleteManufacturer,
apiFetchManufacturers,
} from "@/helpers/api/apiManufacturers";

/**
* Icon and associated action to delete a manufacturer
* @param {*} manufacturer
* @param {*} logout
* @param {*} setManufacturers
* @param {*} setError
* @returns
*/
const DeleteManufacturerActionIcon = ({
manufacturer,
logout,
setManufacturers,
setError,
}) => {
/* Callback to prompt for confirmation and delete amanufacturer */
const confirmDeleteManufacturer = useCallback(
async (e) => {
// Prevent the default action associated with the click event
e.preventDefault();

// Show a confirmation message and get the user response
const message = `This will delete the manufacturer "${manufacturer.name}" - click OK to confirm`;
const result = confirm(message);

// If they've confirmed the deletion ...
if (result) {
// ... delete the manufacturer and confirm the API call was successful
try {
const result = await apiDeleteManufacturer(manufacturer.id, logout);
if (result) {
// Successful, so refresh the manufacturer list
const fetchedManufacturers = await apiFetchManufacturers(logout);
setManufacturers(fetchedManufacturers);
}
} catch (ex) {
setError(`Error deleting the equipment type: ${ex.message}`);
}
}
},
[manufacturer, logout, setManufacturers, setError]
);

return (
<FontAwesomeIcon
icon={faTrashAlt}
onClick={(e) => confirmDeleteManufacturer(e)}
/>
);
};

export default DeleteManufacturerActionIcon;
113 changes: 113 additions & 0 deletions src/music-catalogue-ui/components/manufacturers/manufacturerEditor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import styles from "./manufacturerEditor.module.css";
import pages from "@/helpers/navigation";
import FormInputField from "../common/formInputField";
import { useState, useCallback } from "react";
import {
apiCreateManufacturer,
apiUpdateManufacturer,
} from "@/helpers/api/apiManufacturers";

/**
* Component to render the manufacturer editor
* @param {*} manufacturer
* @param {*} navigate
* @param {*} logout
*/
const EquipmentTypeEditor = ({ manufacturer, navigate, logout }) => {
// Set up state
const initialName = manufacturer != null ? manufacturer.name : null;
const [name, setName] = useState(initialName);
const [error, setError] = useState("");

const saveManufacturer = useCallback(
async (e) => {
// Prevent the default action associated with the click event
e.preventDefault();

// Clear pre-existing errors
setError("");

try {
// Either add or update the manufacturer, depending on whether there's an
// existing manufacturer or not
let updatedEquipmentType = null;
if (manufacturer == null) {
// Create the manufacturer
updatedEquipmentType = await apiCreateManufacturer(name, logout);
} else {
// Update the existing manufacturer
updatedEquipmentType = await apiUpdateManufacturer(
manufacturer.id,
name,
logout
);
}

// Go back to the manufacturer list, which should reflect the updated details
navigate({
page: pages.manufacturers,
});
} catch (ex) {
setError(
`Error saving the updated manufacturer details: ${ex.message}`
);
}
},
[manufacturer, logout, name, navigate]
);

// Set the page title
const pageTitle =
manufacturer != null ? manufacturer.name : "New Manufacturer";

return (
<>
<div className="row mb-2 pageTitle">
<h5 className="themeFontColor text-center">{pageTitle}</h5>
</div>
<div className={styles.manufacturerEditorFormContainer}>
<form className={styles.manufacturerEditorForm}>
<div className="row">
{error != "" ? (
<div className={styles.manufacturerEditorError}>{error}</div>
) : (
<></>
)}
</div>
<div className="row align-items-start">
<FormInputField
label="Name"
name="name"
value={name}
setValue={setName}
/>
</div>
<div className="d-grid gap-2 mt-3"></div>
<div className="d-grid gap-2 mt-3"></div>
<div className={styles.manufacturerEditorButton}>
<button
className="btn btn-primary"
onClick={(e) => saveManufacturer(e)}
>
Save
</button>
</div>
<div className={styles.manufacturerEditorButton}>
<button
className="btn btn-primary"
onClick={() =>
navigate({
page: pages.manufacturers,
})
}
>
Cancel
</button>
</div>
</form>
</div>
</>
);
};

export default EquipmentTypeEditor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.manufacturerEditorFormContainer {
display: flex;
justify-content: center;
align-items: center;
}

.manufacturerEditorForm {
width: 80%;
padding-top: 20px;
padding-bottom: 20px;
}

.manufacturerEditorFormLabel {
font-size: 14px;
font-weight: 600;
color: rgb(34, 34, 34);
}

.manufacturerEditorButton {
margin-left: 10px;
float: right;
}

.manufacturerEditorError {
font-weight: bold;
color: red;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import styles from "./manufacturerList.module.css";
import pages from "@/helpers/navigation";
import useManufacturers from "@/hooks/useManufacturers";
import { useState } from "react";
import ManufacturerRow from "./manufacturerRow";

/**
* Component to render a table listing all the manufacturers in the register
* @param {*} navigate
* @param {*} logout
* @returns
*/
const ManufacturerList = ({ navigate, logout }) => {
const { manufacturers, setManufacturers } = useManufacturers(logout);
const [error, setError] = useState("");

return (
<>
<div className="row mb-2 pageTitle">
<h5 className="themeFontColor text-center">Manufacturers</h5>
</div>
<div className="row">
{error != "" ? (
<div className={styles.manufacturerListError}>{error}</div>
) : (
<></>
)}
</div>
<table className="table table-hover">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
{manufacturers != null && (
<tbody>
{manufacturers.map((m) => (
<ManufacturerRow
key={m.id}
manufacturer={m}
navigate={navigate}
logout={logout}
setManufacturers={setManufacturers}
setError={setError}
/>
))}
</tbody>
)}
</table>
<div className={styles.manufacturerListAddButton}>
<button
className="btn btn-primary"
onClick={() =>
navigate({
page: pages.manufacturerEditor,
})
}
>
Add
</button>
</div>
</>
);
};

export default ManufacturerList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.manufacturerListAddButton {
float: right;
}

.manufacturerListError {
font-weight: bold;
color: red;
text-align: center;
}
Loading

0 comments on commit fd02748

Please sign in to comment.