@fleetbase/storefront-engine
Version:
Headless Commerce & Marketplace Extension for Fleetbase
450 lines (427 loc) • 14.9 kB
JavaScript
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 {
notifications;
intl;
modalsManager;
crud;
fetch;
filters;
hostRouter;
storefront;
page = 1;
limit;
query;
sort = '-created_at';
public_id;
internal_id;
tracking;
facilitator;
customer;
driver;
payload;
pickup;
dropoff;
updated_by;
created_by;
status;
currency = 'USD';
queryParams = [
'page',
'limit',
'sort',
'query',
'public_id',
'internal_id',
'payload',
'tracking_number',
'facilitator',
'customer',
'driver',
'pickup',
'dropoff',
'created_by',
'updated_by',
'status',
];
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
*/
*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;
}
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
*/
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,
});
}
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,
});
}
deleteOrder(order, options = {}) {
this.crud.delete(order, {
onSuccess: () => {
return this.hostRouter.refresh();
},
...options,
});
}
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();
},
});
}
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();
},
});
}
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();
},
});
}
}