@fleetbase/storefront-engine
Version:
Headless Commerce & Marketplace Extension for Fleetbase
304 lines (258 loc) • 9.93 kB
JavaScript
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
import ProductAddonCategoryModel from './product-addon-category';
import AddonCategoryModel from './addon-category';
import { tracked } from '@glimmer/tracking';
import { getOwner } from '@ember/application';
import { setProperties } from '@ember/object';
import { isEmpty } from '@ember/utils';
import { underscore } from '@ember/string';
import { format, formatDistanceToNow } from 'date-fns';
export default class ProductModel extends Model {
/** @ids */
created_by_uuid;
company_uuid;
store_uuid;
category_uuid;
primary_image_uuid;
public_id;
/** @relationships */
category;
primary_image;
files;
variants;
addon_categories;
hours;
catalogCategories;
/** @attributes */
name;
description;
primary_image_url;
sku;
currency;
price;
sale_price;
tags;
youtube_urls;
translations;
meta;
meta_array;
is_on_sale;
is_recommended;
is_service;
is_available;
is_bookable;
status;
slug;
/** @tracked */
isLoadingVariants = false;
isLoadingAddons = false;
isLoadingFiles = false;
isLoadingHours = false;
/** @dates */
created_at;
updated_at;
/** @methods */
toJSON() {
return {
uuid: this.id,
created_by_uuid: this.created_by_uuid,
company_uuid: this.company_uuid,
store_uuid: this.store_uuid,
category_uuid: this.category_uuid,
primary_image_uuid: this.primary_image_uuid,
public_id: this.public_id,
name: this.name,
category: this.category,
primary_image: this.primary_image,
files: this.files,
variants: this.variants,
addon_categories: this.addon_categories,
hours: this.hours,
description: this.description,
primary_image_url: this.primary_image_url,
sku: this.sku,
currency: this.currency,
price: this.price,
sale_price: this.sale_price,
tags: this.tags,
youtube_urls: this.youtube_urls,
translations: this.translations,
is_on_sale: this.is_on_sale,
is_recommended: this.is_recommended,
is_service: this.is_service,
is_available: this.is_available,
is_bookable: this.is_bookable,
status: this.status,
slug: this.slug,
created_at: this.created_at,
updated_at: this.updated_at,
};
}
/** @computed */
get updatedAgo() {
return formatDistanceToNow(this.updated_at);
}
get updatedAt() {
return format(this.updated_at, 'PPP');
}
get createdAgo() {
return formatDistanceToNow(this.created_at);
}
get createdAt() {
return format(this.created_at, 'PPP p');
}
/** @methods */
serializeMeta() {
let { meta_array } = this;
if (isEmpty(meta_array)) {
return this;
}
const serialized = {};
for (let i = 0; i < meta_array.length; i++) {
const metaField = meta_array.objectAt(i);
const { label, value } = metaField;
if (!label) {
continue;
}
serialized[underscore(label)] = value;
}
setProperties(this, { meta: serialized });
return this;
}
loadAddonCategories() {
const owner = getOwner(this);
const store = owner.lookup(`service:store`);
this.isLoadingAddons = true;
return new Promise((resolve) => {
return store
.query('product-addon-category', { product_uuid: this.id, with: ['category'] })
.then((productAddonCategories) => {
this.addon_categories = productAddonCategories;
this.isLoadingAddons = false;
resolve(productAddonCategories);
})
.catch((error) => {
this.isLoadingAddons = false;
resolve([]);
throw error;
});
});
}
loadVariants() {
const owner = getOwner(this);
const store = owner.lookup(`service:store`);
this.isLoadingVariants = true;
return new Promise((resolve) => {
return store
.query('product-variant', { product_uuid: this.id, with: ['options'] })
.then((variants) => {
this.variants = variants;
this.isLoadingVariants = false;
resolve(variants);
})
.catch((error) => {
this.isLoadingVariants = false;
resolve([]);
throw error;
});
});
}
loadHours() {
const owner = getOwner(this);
const store = owner.lookup(`service:store`);
this.isLoadingHours = true;
return new Promise((resolve) => {
return store
.query('product-hour', { product_uuid: this.id })
.then((hours) => {
this.hours = hours;
this.isLoadingHours = false;
resolve(hours);
})
.catch((error) => {
this.isLoadingHours = false;
resolve([]);
throw error;
});
});
}
loadFiles() {
const owner = getOwner(this);
const store = owner.lookup(`service:store`);
this.isLoadingFiles = true;
return new Promise((resolve) => {
return store
.query('file', { subject_uuid: this.id, type: 'storefront_product' })
.then((files) => {
this.files = files;
// set the primary image if applicable
for (let i = 0; i < files.length; i++) {
const file = files.objectAt(i);
if (file.id === this.primary_image_uuid) {
this.primary_image = file;
break;
}
}
this.isLoadingFiles = false;
resolve(files);
})
.catch((error) => {
this.isLoadingFiles = false;
resolve([]);
throw error;
});
});
}
createAddonCategory(category) {
const owner = getOwner(this);
const store = owner.lookup('service:store');
if (store) {
const productAddonCategory = store.createRecord('product-addon-category', {
product_uuid: this.id,
category_uuid: category.id,
name: category.name,
excluded_addons: [],
category,
});
this.addon_categories.pushObject(productAddonCategory);
}
}
doesProductAddonCategoryExist(category) {
const productAddonCategories = this.addon_categories;
return productAddonCategories.find((_) => _.category_uuid === category.id) !== undefined;
}
isProductAddonCategory(_) {
return _ instanceof ProductAddonCategoryModel;
}
isAddonCategory(_) {
return _ instanceof AddonCategoryModel;
}
incomingCategoriesIsMissingExistingAddonCategory(incomingAddonCategories = [], existingProductAddonCategory) {
const existingProductCategoryFromIncoming = incomingAddonCategories.find((addonCategory) => {
if (this.isAddonCategory(addonCategory)) {
return addonCategory.id === existingProductAddonCategory.category_uuid;
}
return addonCategory.category_uuid === existingProductAddonCategory.category_uuid;
});
return existingProductCategoryFromIncoming === undefined;
}
syncProductAddonCategories(incomingAddonCategories = []) {
// remove old categories first
const productAddonCategories = this.addon_categories;
for (let i = 0; i < productAddonCategories.length; i++) {
const productAddonCategory = productAddonCategories[i];
if (this.incomingCategoriesIsMissingExistingAddonCategory(incomingAddonCategories, productAddonCategory)) {
this.addon_categories = productAddonCategories.filter((_) => _.id !== productAddonCategory.id);
productAddonCategory.destroyRecord();
}
}
// add incoming non existing addon categories
for (let i = 0; i < incomingAddonCategories.length; i++) {
const incomingAddonCategory = incomingAddonCategories[i];
if (this.isProductAddonCategory(incomingAddonCategory) || this.doesProductAddonCategoryExist(incomingAddonCategory)) {
continue;
}
this.createAddonCategory(incomingAddonCategory);
}
}
}