Задача №4

Склад. База товарів, які зберігаються на складі: назва товару, одиниця виміру, кількість, фірма виробник (назва, реєстраційний номер). Організувати реєстрацію/відвантаження товарів, фільтрація за назвою товару, фільтрація за назвою фірми.


Рішення:

'use strict'

/** Represents a manufacturer with a name and registration number. */
class Manufacturer {
  /**
   * @param {Object} params
   * @param {string} params.name
   * @param {string} params.registrationNumber
   */
  constructor({name, registrationNumber}) {
    this.name = name
    this.registrationNumber = registrationNumber
  }

  toString() {
    return `Manufacturer "${this.name}", reg: #${this.registrationNumber}.`
  }
}

/** Represents a product with specific details. */
class Product {
  #amount

  /**
   * @param {Object} params - The parameters for the product.
   * @param {string} params.title - The title or name of the product.
   * @param {string} params.measurement - The unit of measurement for the product.
   * @param {number} params.amount - The quantity of the product.
   * @param {Manufacturer} params.manufacturer - The manufacturer of the product.
   */
  constructor({title, measurement, amount, manufacturer}) {
    this.title = title
    this.measurement = measurement
    this.amount = amount
    this.manufacturer = manufacturer
  }

  get amount() {
    return this.#amount
  }

  set amount(newAmount) {
    if (newAmount < 0) throw new Error("An amount can't be negative.")

    this.#amount = newAmount
  }

  toString() {
    return `Product "${this.title}", ${this.measurement}(s) * ${this.amount}, made by "${this.manufacturer.name}".`
  }
}

/** Represent a store with methods to add, find & delete products */
class Store {
  /**
   * @param {string} title - A name of the store.
   */
  constructor(title) {
    this.title = title
    /** @type {{ id: number, data: Product }[]} */
    this.productList = []
  }

  /** @param {Product} product */
  isProductRegistered(product) {
    return !!this.productList.find(({data}) => data === product)
  }

  /** @param {Product} product */
  addProduct(product) {
    if (this.isProductRegistered(product))
      throw new Error(`The product ${product} is already here.`)

    this.productList.push({
      id: new Date().getTime(),
      data: product,
    })
  }

  /**
   * @param {Product} product
   */
  removeProduct(product) {
    const productIndex = this.productList.findIndex(
      ({data}) => data === product,
    )

    if (productIndex === -1) throw new Error(`There's no ${product.title}.`)

    this.productList.splice(productIndex, 1)
  }

  /**
   * @param {number} productId
   */
  removeProductById(productId) {
    const productIndex = this.productList.findIndex(({id}) => id === productId)

    if (productIndex === -1)
      throw new Error(`There's no product with the "${productId}" id.`)

    this.productList.splice(productIndex, 1)
  }

  /**
   * @param {string} productTitle
   */
  removeProductsByTitle(productTitle) {
    this.productList = this.productList.filter(
      ({data: {title}}) => title !== productTitle,
    )
  }

  /**
   * @param {string} productTitle
   */
  getProductsByTitle(productTitle) {
    return this.productList.filter(({data: {title}}) => title === productTitle)
  }

  /**
   * @param {string} manufacturerName
   */
  getProductsByManufacturer(manufacturerName) {
    return this.productList.filter(
      ({
        data: {
          manufacturer: {name},
        },
      }) => name === manufacturerName,
    )
  }

  toString() {
    return (
      `Store "${this.title}"\n` +
      this.productList.map(({data}) => data).join('\n')
    )
  }
}

// Create some manufacturers
const acmeCorp = new Manufacturer({
  name: 'Acme Corp',
  registrationNumber: 'ACME12345',
})
const betaIndustries = new Manufacturer({
  name: 'Beta Industries',
  registrationNumber: 'BETA67890',
})
const gammaLtd = new Manufacturer({
  name: 'Gamma Ltd',
  registrationNumber: 'GAMMA11223',
})

// Create 10 products
const productList = [
  new Product({
    title: 'Laptop Model X',
    measurement: 'unit',
    amount: 50,
    manufacturer: acmeCorp,
  }),
  new Product({
    title: 'Smartphone Z',
    measurement: 'unit',
    amount: 100,
    manufacturer: betaIndustries,
  }),
  new Product({
    title: 'Gaming Mouse',
    measurement: 'unit',
    amount: 200,
    manufacturer: acmeCorp,
  }),
  new Product({
    title: 'Mechanical Keyboard',
    measurement: 'unit',
    amount: 150,
    manufacturer: gammaLtd,
  }),
  new Product({
    title: '4K Monitor',
    measurement: 'unit',
    amount: 75,
    manufacturer: betaIndustries,
  }),
  new Product({
    title: 'Wireless Headphones',
    measurement: 'unit',
    amount: 120,
    manufacturer: acmeCorp,
  }),
  new Product({
    title: 'Tablet Pro',
    measurement: 'unit',
    amount: 60,
    manufacturer: gammaLtd,
  }),
  new Product({
    title: 'Smartwatch Lite',
    measurement: 'unit',
    amount: 90,
    manufacturer: betaIndustries,
  }),
  new Product({
    title: 'USB-C Cable (1m)',
    measurement: 'unit',
    amount: 500,
    manufacturer: acmeCorp,
  }),
  new Product({
    title: 'Portable SSD (1TB)',
    measurement: 'unit',
    amount: 30,
    manufacturer: gammaLtd,
  }),
]

// ---

try {
  const telemart = new Store('Telemart')

  productList.forEach((product) => telemart.addProduct(product))
  console.log('Products in the store', telemart.productList.length)
  telemart.removeProductsByTitle('Mechanical Keyboard')
  console.log('Products in the store', telemart.productList.length)
  console.log(
    `Is the product "${productList[3].title}" inside:`,
    telemart.isProductRegistered(productList[3]),
  )
  console.log(
    `Is the product "${productList[0].title}" inside:`,
    telemart.isProductRegistered(productList[0]),
  )
  console.log('Product "Tablet Pro"', telemart.getProductsByTitle('Tablet Pro'))
  telemart.removeProduct(productList[5])
  console.log('Product "4K Monitor"', telemart.getProductsByTitle('4K Monitor'))
  console.log(
    'Products by manufactured "Gamma Ltd"',
    telemart.getProductsByManufacturer('Gamma Ltd'),
  )
  console.log(String(telemart))
} catch (error) {
  console.error('Caught', error)
}