@lipagas/storefront-engine
Version:
Headless Commerce & Marketplace Extension for Fleetbase
211 lines (188 loc) • 6.2 kB
JavaScript
import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { camelize } from '@ember/string';
import getModelName from '@lipagas/ember-core/utils/get-model-name';
import getWithDefault from '@lipagas/ember-core/utils/get-with-default';
import isObject from '@lipagas/ember-core/utils/is-object';
/**
* Service for managing the state and interactions of the context panel.
*
* @class ContextPanelService
* @memberof @lipagas/storefront
* @extends Service
*/
export default class ContextPanelService extends Service {
/**
* Registry mapping model names to their corresponding component details.
* @type {Object}
*/
registry = {
customer: {
viewing: {
component: 'customer-panel',
componentArguments: [{ isResizable: true }, { width: '500px' }],
},
},
order: {
viewing: {
component: 'order-panel',
componentArguments: [{ isResizable: true }, { width: '500px' }],
},
},
};
/**
* The current context or model object.
* @type {Object}
* @tracked
*/
currentContext;
/**
* The current registry configuration for the current context.
* @type {Object}
* @tracked
*/
currentContextRegistry;
/**
* Arguments for the current context component.
* @type {Object}
* @tracked
*/
currentContextComponentArguments = {};
/**
* Additional options for controlling the context.
* @type {Object}
* @tracked
*/
contextOptions = {};
/**
* Focuses on a given model and intent.
*
* @method
* @param {Object} model - The model to focus on.
* @param {String} [intent='viewing'] - The type of intent ('viewing' or 'editing').
* @action
*/
focus(model, intent = 'viewing', options = {}) {
// handle focus which is not based on a model resource
// this is purely intent
if (typeof model === 'string') {
if (isObject(intent)) {
options = intent;
}
const registry = this.registry[model];
const dynamicArgs = getWithDefault(options, 'args', {});
if (registry) {
this.currentContext = null;
this.currentContextRegistry = registry;
this.currentContextComponentArguments = this.createDynamicArgsFromRegistry(registry, model, dynamicArgs);
this.contextOptions = options;
return this;
}
throw new Error(`Unable to focus selected context: ${model}`);
}
const modelName = getModelName(model);
const registry = this.getRegistryFromModelName(modelName);
const dynamicArgs = getWithDefault(options, 'args', {});
if (registry && registry[intent]) {
this.currentContext = model;
this.currentContextRegistry = registry[intent];
this.currentContextComponentArguments = this.createDynamicArgsFromRegistry(registry[intent], model, dynamicArgs);
this.contextOptions = options;
return this;
}
}
/**
* Get the correct registry from the modelName provided.
*
* @param {string} modelName
* @return {object}
* @memberof ContextPanelService
*/
getRegistryFromModelName(modelName) {
if (typeof modelName === 'string' && modelName.includes('-')) {
modelName = camelize(modelName);
}
return this.registry[modelName];
}
/**
* Clears the current context and associated details.
*
* @method
* @action
*/
clear() {
this.currentContext = null;
this.currentContextRegistry = null;
this.currentContextComponentArguments = {};
this.contextOptions = {};
}
/**
* Changes the intent for the current context.
*
* @method
* @param {String} intent - The new intent.
* @action
*/
changeIntent(intent) {
if (this.currentContext) {
return this.focus(this.currentContext, intent);
}
}
/**
* Sets an option key-value pair.
*
* @method
* @param {String} key - The option key.
* @param {*} value - The option value.
*/
setOption(key, value) {
this.contextOptions = {
...this.contextOptions,
[key]: value,
};
}
/**
* Retrieves the value of an option key.
*
* @method
* @param {String} key - The option key.
* @param {*} [defaultValue=null] - The default value to return if the key is not found.
* @returns {*}
*/
getOption(key, defaultValue = null) {
const value = this.contextOptions[key];
if (value === undefined) {
return defaultValue;
}
return value;
}
/**
* Generates dynamic arguments for a given registry and model.
*
* @method
* @param {Object} registry - The registry details for a given model.
* @param {Object} model - The model object.
* @returns {Object} The dynamic arguments.
*/
createDynamicArgsFromRegistry(registry, model, additionalArgs = {}) {
// Generate dynamic arguments object
const dynamicArgs = {
[camelize(getModelName(model))]: model,
};
const componentArguments = registry.componentArguments || [];
componentArguments.forEach((arg, index) => {
if (typeof arg === 'string') {
dynamicArgs[arg] = model[arg]; // Map string arguments to model properties
} else if (typeof arg === 'object' && arg !== null) {
Object.assign(dynamicArgs, arg);
} else {
// Handle other types of arguments as needed
dynamicArgs[`arg${index}`] = arg;
}
});
// Merge additional args
Object.assign(dynamicArgs, additionalArgs);
return dynamicArgs;
}
}