UNPKG

@fleetbase/storefront-engine

Version:

Headless Commerce & Marketplace Extension for Fleetbase

450 lines (427 loc) 14.9 kB
import BaseController from '@fleetbase/storefront-engine/controllers/base-controller'; import { tracked } from '@glimmer/tracking'; import { action, get } from '@ember/object'; import { inject as service } from '@ember/service'; import { isBlank } from '@ember/utils'; import { isArray } from '@ember/array'; import { timeout, task } from 'ember-concurrency'; export default class OrdersIndexController extends BaseController { @service notifications; @service intl; @service modalsManager; @service crud; @service fetch; @service filters; @service hostRouter; @service storefront; @tracked page = 1; @tracked limit; @tracked query; @tracked sort = '-created_at'; @tracked public_id; @tracked internal_id; @tracked tracking; @tracked facilitator; @tracked customer; @tracked driver; @tracked payload; @tracked pickup; @tracked dropoff; @tracked updated_by; @tracked created_by; @tracked status; @tracked currency = 'USD'; @tracked queryParams = [ 'page', 'limit', 'sort', 'query', 'public_id', 'internal_id', 'payload', 'tracking_number', 'facilitator', 'customer', 'driver', 'pickup', 'dropoff', 'created_by', 'updated_by', 'status', ]; @tracked columns = [ { label: this.intl.t('storefront.common.id'), valuePath: 'public_id', width: '130px', cellComponent: 'table/cell/anchor', onClick: this.viewOrder, resizable: true, sortable: true, filterable: true, filterComponent: 'filter/string', }, { label: this.intl.t('storefront.orders.index.internal-id'), valuePath: 'internal_id', width: '125px', resizable: true, sortable: true, filterable: true, hidden: true, filterComponent: 'filter/string', }, { label: this.intl.t('storefront.orders.index.customer'), valuePath: 'customer.name', cellComponent: 'table/cell/base', width: '100px', resizable: true, sortable: true, hidden: false, filterable: true, filterComponent: 'filter/model', filterComponentPlaceholder: this.intl.t('storefront.orders.index.select-order-customer'), filterParam: 'customer', model: 'customer', }, { label: this.intl.t('storefront.orders.index.total'), cellComponent: 'table/cell/currency', currency: this.currency, valuePath: 'meta.total', width: '100px', resizable: true, hidden: false, sortable: true, }, { label: this.intl.t('storefront.common.pickup'), valuePath: 'pickupName', cellComponent: 'table/cell/base', width: '150px', resizable: true, sortable: true, filterable: true, filterComponent: 'filter/model', filterComponentPlaceholder: this.intl.t('storefront.orders.index.select-order-pickup-location'), filterParam: 'pickup', model: 'place', }, { label: this.intl.t('storefront.common.dropoff'), valuePath: 'dropoffName', cellComponent: 'table/cell/base', width: '150px', resizable: true, sortable: true, filterable: true, filterComponent: 'filter/model', filterComponentPlaceholder: this.intl.t('storefront.orders.index.select-order-dropoff-location'), filterParam: 'dropoff', model: 'place', }, { label: this.intl.t('storefront.orders.index.driver-assigned'), cellComponent: 'table/cell/driver-name', valuePath: 'driver_assigned', modelPath: 'driver_assigned', width: '150px', resizable: true, sortable: true, filterable: true, filterComponent: 'filter/model', filterComponentPlaceholder: this.intl.t('storefront.orders.index.select-driver-for-order'), filterParam: 'driver', model: 'driver', query: { // no model, serializer, adapter for relations without: ['fleets', 'vendor', 'vehicle', 'currentJob'], }, }, { label: this.intl.t('storefront.orders.index.scheduled-at'), valuePath: 'scheduledAt', sortParam: 'scheduled_at', filterParam: 'scheduled_at', width: '125px', resizable: true, sortable: true, filterable: true, hidden: true, filterComponent: 'filter/date', }, { label: '# Items', cellComponent: 'table/cell/base', valuePath: 'item_count', resizable: true, hidden: true, width: '50px', }, { label: this.intl.t('storefront.orders.index.tracking-number'), cellComponent: 'table/cell/base', valuePath: 'tracking_number.tracking_number', width: '160px', resizable: true, sortable: true, filterable: true, filterComponent: 'filter/string', }, { label: this.intl.t('storefront.common.type'), cellComponent: 'cell/humanize', valuePath: 'type', width: '100px', resizable: true, hidden: true, sortable: true, }, { label: this.intl.t('storefront.common.status'), valuePath: 'status', cellComponent: 'table/cell/status', width: '140px', resizable: true, sortable: true, filterable: true, filterComponent: 'filter/multi-option', // filterOptions: this.statusOptions, }, { label: this.intl.t('storefront.orders.index.created-at'), valuePath: 'createdAtShort', sortParam: 'created_at', filterParam: 'created_at', width: '100px', resizable: true, sortable: true, filterable: true, filterComponent: 'filter/date', }, { label: this.intl.t('storefront.orders.index.updated-at'), valuePath: 'updatedAtShort', sortParam: 'updated_at', filterParam: 'updated_at', width: '125px', resizable: true, sortable: true, hidden: true, filterable: true, filterComponent: 'filter/date', }, { label: this.intl.t('storefront.orders.index.created-by'), valuePath: 'created_by_name', width: '125px', resizable: true, hidden: true, filterable: true, filterComponent: 'filter/model', filterComponentPlaceholder: 'Select user', filterParam: 'created_by', model: 'user', }, { label: this.intl.t('storefront.orders.index.updated-by'), valuePath: 'updated_by_name', width: '125px', resizable: true, hidden: true, filterable: true, filterComponent: 'filter/model', filterComponentPlaceholder: this.intl.t('storefront.orders.index.select-user'), filterParam: 'updated_by', model: 'user', }, { label: '', cellComponent: 'table/cell/dropdown', ddButtonText: false, ddButtonIcon: 'ellipsis-h', ddButtonIconPrefix: 'fas', ddMenuLabel: 'Order Actions', cellClassNames: 'overflow-visible', wrapperClass: 'flex items-center justify-end mx-2', width: '90px', actions: [ { label: this.intl.t('fleet-ops.operations.orders.index.view-order'), icon: 'eye', fn: this.viewOrder, permission: 'fleet-ops view order', }, { label: this.intl.t('fleet-ops.operations.orders.index.dispatch-order'), icon: 'paper-plane', fn: this.dispatchOrder, permission: 'fleet-ops dispatch order', isVisible: (order) => order.canBeDispatched, }, { label: this.intl.t('fleet-ops.operations.orders.index.cancel-order'), icon: 'ban', fn: this.cancelOrder, permission: 'fleet-ops cancel order', }, { separator: true, }, { label: this.intl.t('fleet-ops.operations.orders.index.delete-order'), icon: 'trash', fn: this.deleteOrder, permission: 'fleet-ops delete order', }, ], sortable: false, filterable: false, resizable: false, searchable: false, }, ]; constructor() { super(...arguments); this.currency = get(this.storefront, 'activeStore.currency'); } /** * The search task. * * @void */ @task({ restartable: true }) *search({ target: { value } }) { // if no query don't search if (isBlank(value)) { this.query = null; return; } // timeout for typing yield timeout(250); // reset page for results if (this.page > 1) { this.page = 1; } // update the query param this.query = value; } @action viewOrder(order) { return this.transitionToRoute('orders.index.view', order); } /** * Cancels a specific order after confirmation. * @param {Object} order - The order to cancel. * @param {Object} [options={}] - Additional options for the modal. * @action * @memberof OperationsOrdersIndexController */ @action cancelOrder(order, options = {}) { this.modalsManager.confirm({ title: this.intl.t('fleet-ops.operations.orders.index.cancel-title'), body: this.intl.t('fleet-ops.operations.orders.index.cancel-body'), order, confirm: async (modal) => { modal.startLoading(); try { await this.fetch.patch('orders/cancel', { order: order.id }); order.set('status', 'canceled'); this.notifications.success(this.intl.t('fleet-ops.operations.orders.index.cancel-success', { orderId: order.public_id })); modal.done(); } catch (error) { this.notifications.serverError(error); modal.stopLoading(); } }, ...options, }); } @action dispatchOrder(order, options = {}) { this.modalsManager.confirm({ title: this.intl.t('fleet-ops.operations.orders.index.dispatch-title'), body: this.intl.t('fleet-ops.operations.orders.index.dispatch-body'), acceptButtonScheme: 'primary', acceptButtonText: 'Dispatch', acceptButtonIcon: 'paper-plane', order, confirm: async (modal) => { modal.startLoading(); try { await this.fetch.patch('orders/dispatch', { order: order.id }); order.set('status', 'dispatched'); this.notifications.success(this.intl.t('fleet-ops.operations.orders.index.dispatch-success', { orderId: order.public_id })); modal.done(); } catch (error) { this.notifications.serverError(error); modal.stopLoading(); } }, ...options, }); } @action deleteOrder(order, options = {}) { this.crud.delete(order, { onSuccess: () => { return this.hostRouter.refresh(); }, ...options, }); } @action bulkDeleteOrders(selected = []) { selected = selected.length > 0 ? selected : this.table.selectedRows; this.crud.bulkDelete(selected, { modelNamePath: `public_id`, acceptButtonText: 'Delete Orders', onSuccess: async () => { await this.hostRouter.refresh(); this.table.untoggleSelectAll(); }, }); } @action bulkCancelOrders(selected = []) { selected = selected.length > 0 ? selected : this.table.selectedRows; if (!isArray(selected) || selected.length === 0) { return; } this.crud.bulkAction('cancel', selected, { acceptButtonText: 'Cancel Orders', acceptButtonScheme: 'danger', acceptButtonIcon: 'ban', modelNamePath: `public_id`, actionPath: `orders/bulk-cancel`, actionMethod: `PATCH`, onConfirm: (canceledOrders) => { canceledOrders.forEach((order) => { order.set('status', 'canceled'); }); }, onSuccess: async () => { await this.hostRouter.refresh(); this.table.untoggleSelectAll(); }, }); } @action bulkDispatchOrders(selected = []) { selected = selected.length > 0 ? selected : this.table.selectedRows; if (!isArray(selected) || selected.length === 0) { return; } this.crud.bulkAction('dispatch', selected, { acceptButtonText: 'Dispatch Orders', acceptButtonScheme: 'magic', acceptButtonIcon: 'rocket', modelNamePath: 'public_id', actionPath: 'orders/bulk-dispatch', actionMethod: 'POST', onConfirm: (dispatchedOrders) => { dispatchedOrders.forEach((order) => { order.set('status', 'dispatched'); }); }, onSuccess: async () => { await this.hostRouter.refresh(); this.table.untoggleSelectAll(); }, }); } }