Skip to content

Commit

Permalink
Implement equipment list and editing options
Browse files Browse the repository at this point in the history
  • Loading branch information
davewalker5 committed Dec 4, 2023
1 parent 8c60613 commit f458800
Show file tree
Hide file tree
Showing 13 changed files with 424 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import RetailerSelector from "../retailers/retailerSelector";
* Form to set the album purchase details for an album
* @param {*} artist
* @param {*} album
* @param {*} isWishList
* @param {*} navigate
* @param {*} logout
*/
Expand Down Expand Up @@ -41,7 +40,7 @@ const AlbumPurchaseDetails = ({ artist, album, navigate, logout }) => {

// Construct the values to be passed to the API
const updatedPurchaseDate =
album.isWishListItem == false ? purchaseDate : null;
album.isWishListItem != true ? purchaseDate : null;
const updatedPrice = price != undefined ? price : null;
const updatedRetailerId = retailer != null ? retailer.id : null;

Expand Down
9 changes: 9 additions & 0 deletions src/music-catalogue-ui/components/componentPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import EquipmentTypeEditor from "./equipmentTypes/equipmentTypeEditor";
import ManufacturerList from "./manufacturers/manufacturerList";
import ManufacturerEditor from "./manufacturers/manufacturerEditor";
import EquipmentList from "./equipment/equipmentList";
import EquipmentPurchaseDetails from "./equipment/equpimentPurchaseDetails";

/**
* Component using the current context to select and render the current page
Expand Down Expand Up @@ -150,6 +151,14 @@ const ComponentPicker = ({ context, navigate, logout }) => {
logout={logout}
/>
);
case pages.equipmentPurchaseDetails:
return (
<EquipmentPurchaseDetails
equipment={context.equipment}
navigate={navigate}
logout={logout}
/>
);
case pages.export:
return <ExportCatalogue logout={logout} />;
case pages.artistStatisticsReport:
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.equipmentEditorFormContainer {
display: flex;
justify-content: center;
align-items: center;
}

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

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

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

.equipmentEditorError {
font-weight: bold;
color: red;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import EquipmentRow from "./equipmentRow";
* @returns
*/
const EquipmentList = ({ isWishList, navigate, logout }) => {
const { equipment, setEquipment } = useEquipment(logout);
const { equipment, setEquipment } = useEquipment(isWishList, logout);
const [error, setError] = useState("");

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.purchaseDetailsFormContainer {
display: flex;
justify-content: center;
align-items: center;
}

.purchaseDetailsForm {
width: 420px;
padding-top: 20px;
padding-bottom: 20px;
}

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

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

.purchaseDetailsError {
font-weight: bold;
color: red;
}
20 changes: 10 additions & 10 deletions src/music-catalogue-ui/components/equipment/equipmentRow.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import pages from "@/helpers/navigation";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faPenToSquare } from "@fortawesome/free-solid-svg-icons";
import { faPenToSquare, faCoins } from "@fortawesome/free-solid-svg-icons";
import DeleteEquipmentActionIcon from "./deleteEquipmentActionIcon";
import DateFormatter from "../common/dateFormatter";
import CurrencyFormatter from "../common/currencyFormatter";
import EquipmentWishListActionIcon from "./equipmentWishListActionIcon";

/**
* Component to render a row containing the details for a single item of equipment
Expand Down Expand Up @@ -70,24 +71,23 @@ const EquipmentRow = ({
/>
</td>
<td>
{/* <AlbumWishListActionIcon
album={album}
<EquipmentWishListActionIcon
equipment={equipment}
isWishList={isWishList}
logout={logout}
setAlbums={setAlbums}
/> */}
setEquipment={setEquipment}
/>
</td>
<td>
{/* <FontAwesomeIcon
<FontAwesomeIcon
icon={faCoins}
onClick={() =>
navigate({
page: pages.albumPurchaseDetails,
artist: artist,
album: album,
page: pages.equipmentPurchaseDetails,
equipment: equipment,
})
}
/> */}
/>
</td>
</tr>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useCallback } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faHeartCirclePlus,
faRecordVinyl,
} from "@fortawesome/free-solid-svg-icons";
import {
apiFetchEquipment,
apiSetEquipmentWishListFlag,
} from "@/helpers/api/apiEquipment";

/**
* Icon and associated action to move an item of equipment between the main
* registry and wish list
* @param {*} equipment
* @param {*} isWishList
* @param {*} logout
* @param {*} setEquipment
* @returns
*/
const EquipmentWishListActionIcon = ({
equipment,
isWishList,
logout,
setEquipment,
}) => {
// Set the icon depending on the direction in which the equipment will move
const icon = isWishList ? faRecordVinyl : faHeartCirclePlus;

/* Callback to move an album between the wish list and catalogue */
const setEquipmentWishListFlag = useCallback(async () => {
// Move the album to the wish list
const result = await apiSetEquipmentWishListFlag(
equipment,
!isWishList,
logout
);
if (result) {
// Successful, so refresh the album list
const fetchedEquipment = await apiFetchEquipment(isWishList, logout);
setEquipment(fetchedEquipment);
}
}, [equipment, isWishList, logout, setEquipment]);

return <FontAwesomeIcon icon={icon} onClick={setEquipmentWishListFlag} />;
};

export default EquipmentWishListActionIcon;
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import styles from "./equipmentPurchaseDetails.module.css";
import DatePicker from "react-datepicker";
import { useState, useCallback } from "react";
import CurrencyInput from "react-currency-input-field";
import config from "@/config.json";
import pages from "@/helpers/navigation";
import RetailerSelector from "../retailers/retailerSelector";
import { apiSetEquipmentPurchaseDetails } from "@/helpers/api/apiEquipment";

/**
* Form to set the equipment purchase details for an item of equipment
* @param {*} equipment
* @param {*} navigate
* @param {*} logout
*/
const EquipmentPurchaseDetails = ({ equipment, navigate, logout }) => {
// Get the initial retailer selection and purchase date
let initialRetailer = null;
let initialPurchaseDate = new Date();
if (equipment != null) {
initialRetailer = equipment.retailer;

if (equipment.purchased != null) {
initialPurchaseDate = new Date(equipment.purchased);
}
}

// Set up state
const [purchaseDate, setPurchaseDate] = useState(initialPurchaseDate);
const [price, setPrice] = useState(equipment.price);
const [retailer, setRetailer] = useState(initialRetailer);
const [errorMessage, setErrorMessage] = useState("");

/* Callback to set album purchase details */
const setEquipmentPurchaseDetails = useCallback(
async (e) => {
// Prevent the default action associated with the click event
e.preventDefault();

// Construct the values to be passed to the API
const updatedPurchaseDate =
equipment.isWishListItem != true ? purchaseDate : null;
const updatedPrice = price != undefined ? price : null;
const updatedRetailerId = retailer != null ? retailer.id : null;

// Apply the updates
const updatedEquipment = await apiSetEquipmentPurchaseDetails(
equipment,
updatedPurchaseDate,
updatedPrice,
updatedRetailerId,
logout
);

// If the returned album is valid, navigate back to the albums by artist page.
// Otherwise, show an error
if (updatedEquipment != null) {
navigate({
page: pages.equipment,
isWishList: updatedEquipment.isWishListItem,
});
} else {
setErrorMessage("Error updating the equipment purchase details");
}
},
[equipment, price, purchaseDate, retailer, logout, navigate]
);

return (
<>
<div className="row mb-2 pageTitle">
<h5 className="themeFontColor text-center">
{equipment.description} - Purchase Details
</h5>
</div>
<div className={styles.purchaseDetailsFormContainer}>
<form className={styles.purchaseDetailsForm}>
<div>
{equipment.isWishListItem == true ? (
<></>
) : (
<div className="form-group mt-3">
<label className={styles.purchaseDetailsFormLabel}>
Purchase Date
</label>
<div>
<DatePicker
selected={purchaseDate}
onChange={(date) => setPurchaseDate(date)}
/>
</div>
</div>
)}
<div className="form-group mt-3">
<label className={styles.purchaseDetailsFormLabel}>Price</label>
<div>
<CurrencyInput
placeholder="Price"
name="price"
defaultValue={price}
decimalsLimit={2}
allowNegativeValue={false}
disableAbbreviations={true}
intlConfig={{
locale: config.region.locale,
currency: config.region.currency,
}}
onValueChange={(value, _) => setPrice(value)}
/>
</div>
</div>
<div className="form-group mt-3">
<label className={styles.purchaseDetailsFormLabel}>
Retailer
</label>
<div>
<RetailerSelector
initialRetailer={retailer}
retailerChangedCallback={setRetailer}
logout={logout}
/>
</div>
</div>
<div className="d-grid gap-2 mt-3">
<span className={styles.purchaseDetailsError}>
{errorMessage}
</span>
</div>
<div className="d-grid gap-2 mt-3"></div>
<div className="d-grid gap-2 mt-3"></div>
<div className={styles.purchaseDetailsButton}>
<button
className="btn btn-primary"
onClick={(e) => setEquipmentPurchaseDetails(e)}
>
Save
</button>
</div>
<div className={styles.purchaseDetailsButton}>
<button
className="btn btn-primary"
onClick={() =>
navigate({
page: pages.albums,
artist: artist,
album: equipment,
isWishList: equipment.isWishListItem,
})
}
>
Cancel
</button>
</div>
</div>
</form>
</div>
</>
);
};

export default EquipmentPurchaseDetails;
Loading

0 comments on commit f458800

Please sign in to comment.