diff --git a/src/music-catalogue-ui/components/albums/albumPurchaseDetails.js b/src/music-catalogue-ui/components/albums/albumPurchaseDetails.js index 8b18e6a..bc1c52f 100644 --- a/src/music-catalogue-ui/components/albums/albumPurchaseDetails.js +++ b/src/music-catalogue-ui/components/albums/albumPurchaseDetails.js @@ -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 */ @@ -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; diff --git a/src/music-catalogue-ui/components/componentPicker.js b/src/music-catalogue-ui/components/componentPicker.js index def9126..d4c9a69 100644 --- a/src/music-catalogue-ui/components/componentPicker.js +++ b/src/music-catalogue-ui/components/componentPicker.js @@ -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 @@ -150,6 +151,14 @@ const ComponentPicker = ({ context, navigate, logout }) => { logout={logout} /> ); + case pages.equipmentPurchaseDetails: + return ( + + ); case pages.export: return ; case pages.artistStatisticsReport: diff --git a/src/music-catalogue-ui/components/equipment/equipmentEditor.js b/src/music-catalogue-ui/components/equipment/equipmentEditor.js new file mode 100644 index 0000000..e69de29 diff --git a/src/music-catalogue-ui/components/equipment/equipmentEditor.module.css b/src/music-catalogue-ui/components/equipment/equipmentEditor.module.css new file mode 100644 index 0000000..d878ad5 --- /dev/null +++ b/src/music-catalogue-ui/components/equipment/equipmentEditor.module.css @@ -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; +} diff --git a/src/music-catalogue-ui/components/equipment/equipmentList.js b/src/music-catalogue-ui/components/equipment/equipmentList.js index cdc1e9b..9e7a389 100644 --- a/src/music-catalogue-ui/components/equipment/equipmentList.js +++ b/src/music-catalogue-ui/components/equipment/equipmentList.js @@ -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 ( diff --git a/src/music-catalogue-ui/components/equipment/equipmentPurchaseDetails.module.css b/src/music-catalogue-ui/components/equipment/equipmentPurchaseDetails.module.css new file mode 100644 index 0000000..1fedcba --- /dev/null +++ b/src/music-catalogue-ui/components/equipment/equipmentPurchaseDetails.module.css @@ -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; +} diff --git a/src/music-catalogue-ui/components/equipment/equipmentRow.js b/src/music-catalogue-ui/components/equipment/equipmentRow.js index 372f836..4163c52 100644 --- a/src/music-catalogue-ui/components/equipment/equipmentRow.js +++ b/src/music-catalogue-ui/components/equipment/equipmentRow.js @@ -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 @@ -70,24 +71,23 @@ const EquipmentRow = ({ /> - {/* */} + setEquipment={setEquipment} + /> - {/* navigate({ - page: pages.albumPurchaseDetails, - artist: artist, - album: album, + page: pages.equipmentPurchaseDetails, + equipment: equipment, }) } - /> */} + /> ); diff --git a/src/music-catalogue-ui/components/equipment/equipmentWishListActionIcon.js b/src/music-catalogue-ui/components/equipment/equipmentWishListActionIcon.js new file mode 100644 index 0000000..9a56588 --- /dev/null +++ b/src/music-catalogue-ui/components/equipment/equipmentWishListActionIcon.js @@ -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 ; +}; + +export default EquipmentWishListActionIcon; diff --git a/src/music-catalogue-ui/components/equipment/equpimentPurchaseDetails.js b/src/music-catalogue-ui/components/equipment/equpimentPurchaseDetails.js new file mode 100644 index 0000000..30aa8fd --- /dev/null +++ b/src/music-catalogue-ui/components/equipment/equpimentPurchaseDetails.js @@ -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 ( + <> +
+
+ {equipment.description} - Purchase Details +
+
+
+
+
+ {equipment.isWishListItem == true ? ( + <> + ) : ( +
+ +
+ setPurchaseDate(date)} + /> +
+
+ )} +
+ +
+ setPrice(value)} + /> +
+
+
+ +
+ +
+
+
+ + {errorMessage} + +
+
+
+
+ +
+
+ +
+
+
+
+ + ); +}; + +export default EquipmentPurchaseDetails; diff --git a/src/music-catalogue-ui/components/equipmentTypes/equipmentTypeSelector.js b/src/music-catalogue-ui/components/equipmentTypes/equipmentTypeSelector.js new file mode 100644 index 0000000..ad867a9 --- /dev/null +++ b/src/music-catalogue-ui/components/equipmentTypes/equipmentTypeSelector.js @@ -0,0 +1,62 @@ +import Select from "react-select"; +import useEquipmentTypes from "@/hooks/useEquipmentTypes"; +import { useState } from "react"; + +/** + * Component to display the equipment type selector + * @param {*} initialEquipmentType + * @param {*} equipmentTypeChangedCallback + * @param {*} logout + * @returns + */ +const EquipmentTypeSelector = ({ + initialEquipmentType, + equipmentTypeChangedCallback, + logout, +}) => { + const { equipmentTypes, setEquipmentTypes } = useEquipmentTypes(logout); + + let options = []; + if (equipmentTypes.length > 0) { + // Construct the options for the drop-down + for (let i = 0; i < equipmentTypes.length; i++) { + options = [ + ...options, + { value: equipmentTypes[i].id, label: equipmentTypes[i].name }, + ]; + } + } + + // Determine the initial selection + let selectedOption = null; + if (initialEquipmentType != null) { + selectedOption = options.find((x) => x.value === initialEquipmentType.id); + } + + // Set up state + const [equipmentType, setEquipmentType] = useState(selectedOption); + + // Callback to update state and notify the parent component + // that the selection has changed + const equipmentTypeChanged = (e) => { + // Update local state with the selection from the drop-down + const updatedSelection = options.find((x) => x.value === e.value); + setEquipmentType(updatedSelection); + + // Notify the parent component with an equipment type object + equipmentTypeChangedCallback({ + id: updatedSelection.value, + name: updatedSelection.label, + }); + }; + + return ( + + ); +}; + +export default ManufacturerSelector; diff --git a/src/music-catalogue-ui/components/menuBar.js b/src/music-catalogue-ui/components/menuBar.js index 720a807..872dfa9 100644 --- a/src/music-catalogue-ui/components/menuBar.js +++ b/src/music-catalogue-ui/components/menuBar.js @@ -61,8 +61,20 @@ const MenuBar = ({ navigate, logout }) => {
- navigate({ page: pages.equipment })}>Equipment - Wish List + + navigate({ page: pages.equipment, isWishList: false }) + } + > + Equipment + + + navigate({ page: pages.equipment, isWishList: true }) + } + > + Wish List + navigate({ page: pages.equipmentTypes })}> Equipment Types diff --git a/src/music-catalogue-ui/helpers/navigation.js b/src/music-catalogue-ui/helpers/navigation.js index 09769e4..4689e45 100644 --- a/src/music-catalogue-ui/helpers/navigation.js +++ b/src/music-catalogue-ui/helpers/navigation.js @@ -5,6 +5,7 @@ const pages = { wishlistArtists: "WishlistArtists", albums: "Albums", albumEditor: "AlbumEditor", + albumPurchaseDetails: "AlbumPurchaseDetails", wishlistAlbums: "WishlistAlbums", tracks: "Tracks", trackEditor: "TrackEditor", @@ -17,6 +18,7 @@ const pages = { manufacturerEditor: "ManufacturerEditor", equipment: "Equipment", equipmentEditor: "EquipmentEditor", + equipmentPurchaseDetails: "EquipmentPurchaseDetails", lookup: "Lookup", export: "Export", artistStatisticsReport: "ArtistStatisticsReport", @@ -24,7 +26,6 @@ const pages = { jobStatusReport: "JobStatusReport", monthlySpendReport: "MonthlySpendReport", retailerStatisticsReport: "RetailerStatisticsReport", - albumPurchaseDetails: "AlbumPurchaseDetails", }; export default pages;