Skip to content

Commit

Permalink
Merge pull request #130 from fleetbase/dev-v0.5.13
Browse files Browse the repository at this point in the history
v0.5.13 - bulk dispatch, service areas/zones creation patch, customer view label
  • Loading branch information
roncodes authored Nov 7, 2024
2 parents d2e9863 + a36ff44 commit ffdccb9
Show file tree
Hide file tree
Showing 16 changed files with 297 additions and 66 deletions.
16 changes: 10 additions & 6 deletions addon/components/customer-panel.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@
</div>
</DropdownButton>
</div>
<Button
@type="default"
@icon="times"
@helpText={{if this.customer.id (t "fleet-ops.component.contact-panel.cancel-edit-button") (t "fleet-ops.component.contact-panel.cancel-new-button")}}
@onClick={{this.onPressCancel}}
/>
<div>
<div class="flex">
<Button
@type="default"
@icon="times"
@helpText={{if this.customer.id (t "fleet-ops.component.contact-panel.cancel-edit-button") (t "fleet-ops.component.contact-panel.cancel-new-button")}}
@onClick={{this.onPressCancel}}
/>
</div>
</div>
</div>
</div>
<div class="flex flex-row justify-between w-full">
Expand Down
54 changes: 39 additions & 15 deletions addon/components/customer/orders.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
</div>
<div>
<div class="flex flew-row space-x-2">
<Button @helpText="View Label" @icon="print" @onClick={{this.viewOrderLabel}} />
<Button @helpText="View Route" @icon="route" @onClick={{this.locateOrderRoute}} />
<Button @helpText="Locate Driver" @icon="truck" @onClick={{this.locateDriver}} @disabled={{not order.has_driver_assigned}} />
</div>
Expand Down Expand Up @@ -169,12 +170,18 @@
{{#each order.payload.entitiesByDestination as |group|}}
<div class="item-detail">
<div class="flex flex-row justify-between flex-grow-0">
<DisplayPlace @place={{group.waypoint}} @addressClass="text-xs truncate" {{set-width "140px"}} />
<div class="flex flex-col" {{set-width "140px"}}>
<DisplayPlace @place={{group.waypoint}} @addressClass="text-xs truncate" />

</div>
<div class="flex flex-col items-end flex-grow-0 space-y-1">
<div class="rounded-md bg-yellow-300 text-yellow-900 px-2 py-0.5 text-xs flex-grow-0">{{t
"fleet-ops.operations.orders.index.view.tracking"
}}
{{group.waypoint.tracking}}</div>
<ClickToCopy
@value={{group.waypoint.tracking}}
class="rounded-md bg-yellow-300 text-yellow-900 px-2 py-0.5 text-xs flex-grow-0 truncate"
>
<span>{{t "fleet-ops.operations.orders.index.view.tracking"}}</span>
<span>{{group.waypoint.tracking}}</span>
</ClickToCopy>
<Badge @status={{group.waypoint.status_code}} />
</div>
</div>
Expand All @@ -187,17 +194,27 @@
</div>
<div class="flex-1">
<div class="text-sm font-bold">{{n-a entity.name (concat "Item " (add index 1))}}</div>
<div class="text-xs"><span class="font-semibold">Description:</span>
{{n-a entity.description "No description provided."}}</div>
<div class="text-xs"><span class="font-semibold">Tracking:</span> {{n-a entity.tracking}}</div>
<div class="text-xs">
<span class="font-semibold">Description:</span>
<span>{{n-a entity.description "No description provided."}}</span>
</div>
<ClickToCopy @value={{entity.tracking}} class="text-xs"><span class="font-semibold">Tracking:</span>
{{n-a entity.tracking}}
</ClickToCopy>
{{#if entity.price}}
<div class="text-xs"><span class="font-semibold">Price:</span>
{{format-currency entity.price entity.currency}}</div>
<div class="text-xs">
<span class="font-semibold">Price:</span>
<span>{{format-currency entity.price entity.currency}}</span>
</div>
{{/if}}
</div>
</div>
{{/each}}
</div>
<div class="customer-order-details-seperator"></div>
<div class="flex">
<Button @helpText="View Label" @icon="print" @size="sm" @onClick={{fn this.viewWaypointLabel group.waypoint}} />
</div>
</div>
{{else}}
<div class="text-xs text-gray-500 px-2">None</div>
Expand All @@ -213,12 +230,19 @@
</div>
<div class="flex-1">
<div class="text-sm font-bold">{{n-a entity.name (concat "Item " (add index 1))}}</div>
<div class="text-xs"><span class="font-semibold">Description:</span>
{{n-a entity.description "No description provided."}}</div>
<div class="text-xs"><span class="font-semibold">Tracking:</span> {{n-a entity.tracking}}</div>
<div class="text-xs">
<span class="font-semibold">Description:</span>
<span>{{n-a entity.description "No description provided."}}</span>
</div>
<ClickToCopy @value={{entity.tracking}} class="text-xs">
<span class="font-semibold">Tracking:</span>
<span>{{n-a entity.tracking}}</span>
</ClickToCopy>
{{#if entity.price}}
<div class="text-xs"><span class="font-semibold">Price:</span>
{{format-currency entity.price entity.currency}}</div>
<div class="text-xs">
<span class="font-semibold">Price:</span>
<span>{{format-currency entity.price entity.currency}}</span>
</div>
{{/if}}
</div>
</div>
Expand Down
64 changes: 64 additions & 0 deletions addon/components/customer/orders.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ const MAP_TARGET_FOCUS_PADDING_BOTTOM_RIGHT = [200, 0];
const MAP_TARGET_FOCUS_REFOCUS_PANBY = [150, 0];
export default class CustomerOrdersComponent extends Component {
@service store;
@service fetch;
@service notifications;
@service currentUser;
@service universe;
@service urlSearchParams;
@service modalsManager;
@service customerSession;
@service hostRouter;
@engineService('@fleetbase/fleetops-engine') movementTracker;
Expand Down Expand Up @@ -144,6 +146,68 @@ export default class CustomerOrdersComponent extends Component {
}
}

@action async viewOrderLabel() {
const order = this.selectedOrder;
if (!order) {
return;
}

// render dialog to display label within
this.modalsManager.show(`modals/order-label`, {
title: 'Order Label',
modalClass: 'modal-xl',
acceptButtonText: 'Done',
hideDeclineButton: true,
order,
});

try {
// load the pdf label from base64
// eslint-disable-next-line no-undef
const fileReader = new FileReader();
const { data } = await this.fetch.get(`orders/label/${order.public_id}?format=base64`);
// eslint-disable-next-line no-undef
const base64 = await fetch(`data:application/pdf;base64,${data}`);
const blob = await base64.blob();
// load into file reader
fileReader.onload = (event) => {
const data = event.target.result;
this.modalsManager.setOption('data', data);
};
fileReader.readAsDataURL(blob);
} catch (error) {
this.notifications.serverError(error);
}
}

@action async viewWaypointLabel(waypoint) {
// render dialog to display label within
this.modalsManager.show(`modals/order-label`, {
title: 'Waypoint Label',
modalClass: 'modal-xl',
acceptButtonText: 'Done',
hideDeclineButton: true,
});

try {
// load the pdf label from base64
// eslint-disable-next-line no-undef
const fileReader = new FileReader();
const { data } = await this.fetch.get(`orders/label/${waypoint.waypoint_public_id}?format=base64`);
// eslint-disable-next-line no-undef
const base64 = await fetch(`data:application/pdf;base64,${data}`);
const blob = await base64.blob();
// load into file reader
fileReader.onload = (event) => {
const data = event.target.result;
this.modalsManager.setOption('data', data);
};
fileReader.readAsDataURL(blob);
} catch (error) {
this.notifications.serverError(error);
}
}

@action unselectOrder() {
this.selectedOrder = null;
this.removeRouteControl();
Expand Down
23 changes: 3 additions & 20 deletions addon/components/leaflet-draw-control.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,11 @@ export default class LeafletDrawControl extends BaseLayer {
];
}

get alwaysCapturedLeafletEvents() {
return [
L.Draw.Event.CREATED,
L.Draw.Event.EDITED,
L.Draw.Event.EDITSTART,
L.Draw.Event.EDITSTOP,
L.Draw.Event.EDITRESIZE,
L.Draw.Event.EDITMOVE,
L.Draw.Event.DELETED,
L.Draw.Event.DRAWSTART,
L.Draw.Event.DRAWSTOP,
];
}

leafletOptions = ['draw', 'edit', 'remove', 'poly', 'position'];

@computed('leafletEvents.[]', 'alwaysCapturedLeafletEvents.[]', 'args') get usedLeafletEvents() {
return this.leafletEvents.filter((eventName) => {
if (this.alwaysCapturedLeafletEvents.includes(eventName)) {
return true;
}

@computed('leafletEvents.[]', 'args') get usedLeafletEvents() {
const leafletEvents = [...this.leafletEvents, ...Object.values(L.Draw.Event)];
return leafletEvents.filter((eventName) => {
eventName = camelize(eventName.replace(':', ' '));
let methodName = `_${eventName}`;
let actionName = `on${classify(eventName)}`;
Expand Down
50 changes: 50 additions & 0 deletions addon/controllers/operations/orders/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,13 @@ export default class OperationsOrdersIndexController extends BaseController {
*/
@tracked drawerTab;

/**
* Filterable status options for orders.
*
* @type {Array}
*/
@tracked statusOptions = [];

/**
* Flag to determine if the layout is 'map'
*
Expand Down Expand Up @@ -576,6 +583,15 @@ export default class OperationsOrdersIndexController extends BaseController {
constructor() {
super(...arguments);
this.listenForOrderEvents();
this.getOrderStatusOptions.perform();
}
@task *getOrderStatusOptions() {
try {
this.statusOptions = yield this.fetch.get('orders/statuses');
} catch (error) {
this.notifications.serverError(error);
}
}
/**
Expand Down Expand Up @@ -941,6 +957,7 @@ export default class OperationsOrdersIndexController extends BaseController {

/**
* Cancels multiple selected orders.
*
* @param {Array} [selected=[]] - Orders selected for cancellation.
* @action
* @memberof OperationsOrdersIndexController
Expand Down Expand Up @@ -971,6 +988,39 @@ export default class OperationsOrdersIndexController extends BaseController {
});
}

/**
* Dispatches multiple selected orders.
*
* @param {Array} [selected=[]] - Orders selected for dispatch.
* @action
* @memberof OperationsOrdersIndexController
*/
@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();
},
});
}

/**
* Triggers when the map container is ready.
* @action
Expand Down
4 changes: 4 additions & 0 deletions addon/styles/fleetops-engine.css
Original file line number Diff line number Diff line change
Expand Up @@ -1588,3 +1588,7 @@ body[data-theme='dark']
padding: 0.5rem;
vertical-align: top;
}

.justify-end-i {
justify-content: end !important;
}
15 changes: 13 additions & 2 deletions addon/templates/operations/orders/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,21 @@
<div class="next-dd-menu mt-2 mx-0">
<div class="px-1">
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.bulkCancelOrders)}} disabled={{cannot "fleet-ops cancel order"}}>
{{t "fleet-ops.operations.orders.index.cancel-orders"}}
<div class="w-6"><FaIcon @icon="ban" @size="sm" /></div>
<div>{{t "fleet-ops.operations.orders.index.cancel-orders"}}</div>
</a>
</div>
<div class="px-1">
<a href="javascript:;" class="text-red-500 next-dd-item" {{on "click" (dropdown-fn dd this.bulkDeleteOrders)}} disabled={{cannot "fleet-ops delete order"}}>
{{t "fleet-ops.operations.orders.index.delete-orders"}}
<div class="w-6"><FaIcon @icon="trash" @size="sm" /></div>
<div>{{t "fleet-ops.operations.orders.index.delete-orders"}}</div>
</a>
</div>
<div class="next-dd-menu-seperator"></div>
<div class="px-1">
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.bulkDispatchOrders)}} disabled={{cannot "fleet-ops dispatch order"}}>
<div class="w-6"><FaIcon @icon="rocket" @size="sm" /></div>
<div>{{t "fleet-ops.operations.orders.index.dispatch-orders"}}</div>
</a>
</div>
</div>
Expand Down
8 changes: 1 addition & 7 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fleetbase/fleetops-api",
"version": "0.5.12",
"version": "0.5.13",
"description": "Fleet & Transport Management Extension for Fleetbase",
"keywords": [
"fleetbase-extension",
Expand Down Expand Up @@ -42,12 +42,6 @@
"phpstan/phpstan": "^1.10.38",
"symfony/var-dumper": "^5.4.29"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/fleetbase/laravel-model-caching"
}
],
"autoload": {
"psr-4": {
"Fleetbase\\FleetOps\\": "server/src/",
Expand Down
2 changes: 1 addition & 1 deletion extension.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Fleet-Ops",
"version": "0.5.12",
"version": "0.5.13",
"description": "Fleet & Transport Management Extension for Fleetbase",
"repository": "https://github.com/fleetbase/fleetops",
"license": "AGPL-3.0-or-later",
Expand Down
Loading

0 comments on commit ffdccb9

Please sign in to comment.