);
} else {
modalContent = (
{this.state.loading && }
Create Return Label?
This will take several seconds...
);
}
return (
{this.state.returnLabelError && }
{modalContent}
);
}
renderTitle() {
const createdAtDateTime = Date.parse(this.props.shopifyOrder.created_at);
const created = formatInTimeZone(createdAtDateTime, DEFAULT_TIMEZONE, 'PPPp z');
const title = (
📦 Order {this.props.bigOrder.shopifyOrderName} for {this.props.shopifyOrder.customer.first_name} {this.props.shopifyOrder.customer.last_name}
);
const createdAt = formatInTimeZone(createdAtDateTime, DEFAULT_TIMEZONE, 'PPPp z');
const fromNow = formatDistanceToNow(createdAtDateTime, { addSuffix: true });
let shopifyButton = (this.props.bigOrder.origin === "Shopify") ? : null
const orderActionsAllowed = this.props.bigOrder.state !== "Shipped" && this.props.bigOrder.state !== "Cancelled";
return (
{title}
Created: {createdAt} ({fromNow})
📦 Big Order Actions...
}>
{orderActionsAllowed && <>
{!this.props.bigOrder.shipmentHold && }
This will update the order's priority -- higher priority will be shipped sooner.
This will force the customer's IPD to be updated.
Admin only. Changing this option may cause BigShipper to use a faster shipping option, if available.
The following will happen when you resend a scan request:
All existing scan requests for this customer will be revoked.
A new scan request will be generated for this customer.
An email will be sent to the customer with a new link for them to start the scanning process.
Any jobs attached to this order will be marked as "destroyed".
The order status will be set to .
This will send a link so the customer can change their IPD.
This will only work if the customer has already completed a scan request.
>}
This will delete the Big Order.
{shopifyButton}
);
}
renderBanners() {
const banners = [];
if (this.props.shopifyOrder.THIS_SHOPIFY_ORDER_WAS_DELETED) {
banners.push(The underlying shopify order was deleted)
}
if (this.props.shopifyOrder.tags.includes("test order") || this.props.shopifyOrder.test === true) {
banners.push(
This is a test order. BE CAREFUL WITH SHIPPING THIS ORDER!
);
}
return <>
{banners}
>;
}
renderShopifyData() {
return (
Shopify Data {(this.props.shopifyOrder.THIS_SHOPIFY_ORDER_WAS_DELETED) && }
);
}
renderChecklist() {
if (this.state.loadingChecklist) {
return (
Checking order status...
)
} else if (this.props.bigOrder.checklistResult) {
let currentState = this.props.bigOrder.state;
let nextAction = this.props.bigOrder.nextAction;
let nextActionMessage = this.props.bigOrder.checklistResult.message;
let nextActionText = nextAction;
if (nextAction === "SendScanRequest") {
nextActionText = "Send scan request email to customer";
} else if (nextAction === "SendScanRequestReminder") {
nextActionText = "Send a scan request reminder email to customer";
}
let shipmentsList = null;
if (this.props.shipments.length > 0) {
shipmentsList = (
<>
{this.props.shipments.map((shipment, shipmentIndex) => {
let color = "green";
if (shipment.status === "Cancelled") {
color = "red";
}
return (
);
}
}
}
return null;
}
renderShipment() {
if (this.props.bigOrder && this.props.bigOrder.state === "Shipped") {
return null;
}
if (this.state.loading) {
return (
Loading shipments...
)
}
if (this.props.bigOrder.shipmentHold) {
return (
There is a Hold on this order preventing shipment!
Reason: {this.props.bigOrder.shipmentHold.reason}
Notes: {this.props.bigOrder.shipmentHold.notes}
This will remove the hold on the order and allow it to be shipped via BigShipper.
);
}
if (this.props.bigOrder.state === "Cancelled") {
return (
This order has been cancelled!
);
}
const fulfilledShipments = this.props.shipments.filter(shipment => ["WaitingForPickup", "InTransit", "Shipped", "DeliveryFailed"].includes(shipment.status));
if (this.state.shipping_summary) {
// HACK HACK HACK
//
// "null" returned as a string. Find out why this is.
const shipmentGroupIds = Object.keys(this.state.shipping_summary.shipmentGroups).filter(id => id != "null");
let inventorySummary = shipmentGroupIds.map((shipmentGroupId, i) => {
let shipment = this.state.shipping_summary.shipmentGroups[shipmentGroupId].shipment;
let inventorySlots = this.state.shipping_summary.shipmentGroups[shipmentGroupId].inventorySlots;
let header = Shipment #{i + 1};
if (inventorySlots) {
let availableSlots = inventorySlots.filter(slot => slot.status === "StockAvailable");
let inventoryStatusModal = (
{this.state.loading && }
{(!this.state.loading && inventorySlots) && {`${availableSlots.length} out of ${inventorySlots.length} Items In Stock`}}
{(!this.state.loading && inventorySlots) && }
);
if (availableSlots.length > 0 && availableSlots.length === inventorySlots.length) {
return (
{header}
Shipment can be completed now:
{inventoryStatusModal}
);
} else {
return (
{header}
Not enough inventory to ship:
{inventoryStatusModal}
);
}
} else if (shipment) {
let color = "green";
return (
{header}
This shipment has already been created:
{this.state.loading && }
{(!this.state.loading) && This shipment is {shipment.status}}
{(!this.state.loading) && }
);
}
});
return Shippability
{inventorySummary}
;
} else {
return null;
}
}
renderPendingScanRequests() {
if (this.state.loadingChecklist) {
return (
Loading scan requests...
)
} else if (this.props.scanRequests) {
const hasScanRequests = this.props.scanRequests.length > 0;
if (hasScanRequests) {
return (
);
}
}
return null;
}
/**
* Groups consecutive history items with the same message into collapsed groups.
* Returns an array of groups, where each group has:
* - items: array of history items in the group
* - message: the shared message
* - count: number of items in the group
*/
groupHistoryItems(history) {
if (!history || history.length === 0) {
return [];
}
const groups = [];
let currentGroup = null;
for (const item of history) {
if (currentGroup && currentGroup.message === item.message) {
// Same message as current group, add to it
currentGroup.items.push(item);
currentGroup.count++;
} else {
// Different message, start a new group
if (currentGroup) {
groups.push(currentGroup);
}
currentGroup = {
items: [item],
message: item.message,
count: 1
};
}
}
// Don't forget the last group
if (currentGroup) {
groups.push(currentGroup);
}
return groups;
}
renderBigOrderStuff() {
if (!this.props.bigOrder) {
return null;
}
// HACK HACK HACK - hard coding here.
const looperAccountId = "cc1d57a8-1351-4581-8350-b067dd504791";
// Group consecutive repeated messages
const historyGroups = this.groupHistoryItems(this.props.bigOrder.history);
const bigOrderHistory = historyGroups.flatMap((group, groupIndex) => {
if (group.count === 1) {
// Single item, render normally
const historyItem = group.items[0];
const accountName = (historyItem.bigscreenAccountId === looperAccountId) ? "factory_looper" : `${historyItem.bigscreenAccountId.substring(0, 8)}`;
let createdAtDateTime = fromUnixTime(historyItem.createdAt / 1000);
const createdAt = formatInTimeZone(createdAtDateTime, DEFAULT_TIMEZONE, 'PPPp z');
return [(
{createdAt}
{accountName}
{historyItem.message}
)];
} else {
// Multiple items with same message - show collapsed or expanded
const isExpanded = this.state.expandedHistoryGroups[groupIndex];
const firstItem = group.items[0];
const lastItem = group.items[group.items.length - 1];
if (isExpanded) {
// Show all items in the group with an option to collapse
return group.items.map((historyItem, itemIndex) => {
const accountName = (historyItem.bigscreenAccountId === looperAccountId) ? "factory_looper" : `${historyItem.bigscreenAccountId.substring(0, 8)}`;
let createdAtDateTime = fromUnixTime(historyItem.createdAt / 1000);
const createdAt = formatInTimeZone(createdAtDateTime, DEFAULT_TIMEZONE, 'PPPp z');
return (
this.toggleHistoryGroup(groupIndex)}
>
{createdAt}
{itemIndex === 0 && }
e.stopPropagation()}>{accountName}
{historyItem.message}
);
});
} else {
// Show collapsed row
let firstCreatedAtDateTime = fromUnixTime(firstItem.createdAt / 1000);
let lastCreatedAtDateTime = fromUnixTime(lastItem.createdAt / 1000);
const firstCreatedAt = formatInTimeZone(firstCreatedAtDateTime, DEFAULT_TIMEZONE, 'PPPp z');
const lastCreatedAt = formatInTimeZone(lastCreatedAtDateTime, DEFAULT_TIMEZONE, 'PPPp z');
const firstAccountName = (firstItem.bigscreenAccountId === looperAccountId) ? "factory_looper" : `${firstItem.bigscreenAccountId.substring(0, 8)}`;
return [(
this.toggleHistoryGroup(groupIndex)}
>
{firstCreatedAt}
→ {lastCreatedAt} e.stopPropagation()}>{firstAccountName}
{group.message}
)];
}
}
});
let createdAtDateTime = fromUnixTime(this.props.bigOrder.createdAt / 1000);
const createdAt = formatInTimeZone(createdAtDateTime, DEFAULT_TIMEZONE, 'PPPp z');
const fromNow = formatDistanceToNow(createdAtDateTime, { addSuffix: true });
return (
);
})}
));
}
if (refundedLineItems.length > 0) {
components.push((
({refundedLineItems.length} Refunded or Cancelled items hidden)
));
}
return <>{components.map((component, index) => {component})}>;
}
renderNextActionModal() {
return (
Send a scan request email to this user? This action may take several seconds.
)
}
renderCreateJobModal() {
return (
This step will create a job for this order. This action may take several seconds while the job is created and the scan verified.
Set an optional priority for the job
)
}
render() {
if (!this.props.bigOrder) {
return null;
}
if (this.props.asTableRow) {
let urlOrderId = this.props.bigOrder.id;
if (this.props.bigOrder.shopifyOrderName) {
urlOrderId = this.props.bigOrder.shopifyOrderName;
}
return (
);
} else {
if (!this.props.shopifyOrder) {
return null;
}
return (