init
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card v-if="lines.length" shadow="never">
|
||||
<template #header>
|
||||
<span>Order cart</span>
|
||||
</template>
|
||||
|
||||
<div class="cms-table-scroll">
|
||||
<el-table :data="lines" stripe class="order-cart-table">
|
||||
<el-table-column label="Product" min-width="140" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<router-link
|
||||
:to="{ name: ROUTE_NAMES.ProductDetail, params: { id: row.productId } }"
|
||||
class="order-line-link"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
{{ row.productTitle }}
|
||||
</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="Variant" min-width="140" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<router-link
|
||||
:to="{
|
||||
name: ROUTE_NAMES.ProductVariantDetail,
|
||||
params: { productId: row.productId, variantId: row.variantId }
|
||||
}"
|
||||
class="order-line-link"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
{{ row.variantTitle }}
|
||||
</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="qty" label="Qty" width="70" />
|
||||
|
||||
<el-table-column label="Unit price" width="120">
|
||||
<template #default="{ row }">
|
||||
{{ formatFiatPrice(row.unitPriceFiat, order.fiatCurrency) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="Line total" width="120">
|
||||
<template #default="{ row }">
|
||||
{{ formatFiatPrice(row.lineSubtotalFiat, order.fiatCurrency) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="Delivery" width="150">
|
||||
<template #default="{ row }">
|
||||
{{ formatDeliveryMode(row.deliveryMode) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="Fulfillment" width="140">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="resolveLineFulfillmentTag(row).type" size="small">
|
||||
{{ resolveLineFulfillmentTag(row).label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="100" fixed="right" align="right" class-name="order-cart-action-col">
|
||||
<template #default="{ row }">
|
||||
<span v-if="order.failureReason" class="secondary-text">—</span>
|
||||
|
||||
<template v-else>
|
||||
<el-button
|
||||
v-if="row.deliveryMode === DeliveryMode.Auto"
|
||||
link
|
||||
type="primary"
|
||||
title="View delivery"
|
||||
@click="openAutoDelivery(row)"
|
||||
>
|
||||
View
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-else-if="!isManualLineFulfilled(row)"
|
||||
link
|
||||
type="primary"
|
||||
title="Mark as fulfilled"
|
||||
:loading="fulfillingLineId === row.id"
|
||||
@click="markAsFulfilled(row)"
|
||||
>
|
||||
Fulfill
|
||||
</el-button>
|
||||
|
||||
<span v-else class="secondary-text">—</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<order-line-auto-fulfillment-modal v-model="autoModalVisible" :line="selectedLine" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, type PropType } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { ROUTE_NAMES } from '@/consts/routeNames';
|
||||
import { useOrdersStore } from '@/stores/orders';
|
||||
import { ManualLineFulfillmentStatus } from '@/types/order/ManualLineFulfillmentStatus';
|
||||
import type { OrderLine } from '@/types/order/OrderLine';
|
||||
import type { OrderExtended } from '@/types/order/OrderExtended';
|
||||
import { DeliveryMode } from '@/types/product/DeliveryMode';
|
||||
import { formatDeliveryMode } from '@/utils/product/formatDeliveryMode';
|
||||
import { formatFiatPrice } from '@/utils/formatFiatPrice';
|
||||
import { resolveAxiosErrorMessage } from '@/utils/resolveAxiosErrorMessage';
|
||||
|
||||
const props = defineProps({
|
||||
order: {
|
||||
type: Object as PropType<OrderExtended>,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const ordersStore = useOrdersStore();
|
||||
|
||||
const { fulfillManualLine } = ordersStore;
|
||||
|
||||
const selectedLine = ref<OrderLine | null>(null);
|
||||
const autoModalVisible = ref(false);
|
||||
const fulfillingLineId = ref<string | null>(null);
|
||||
|
||||
const lines = computed(() => props.order.lines ?? []);
|
||||
|
||||
const isManualLineFulfilled = (line: OrderLine): boolean =>
|
||||
line.manualFulfillment?.status === ManualLineFulfillmentStatus.Fulfilled;
|
||||
|
||||
const openAutoDelivery = (line: OrderLine): void => {
|
||||
selectedLine.value = line;
|
||||
autoModalVisible.value = true;
|
||||
};
|
||||
|
||||
const markAsFulfilled = async (line: OrderLine): Promise<void> => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`Mark "${line.productTitle}" (${line.variantTitle}) as fulfilled? This cannot be undone.`,
|
||||
'Mark as fulfilled',
|
||||
{
|
||||
type: 'warning',
|
||||
confirmButtonText: 'Mark fulfilled',
|
||||
cancelButtonText: 'Cancel'
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
fulfillingLineId.value = line.id;
|
||||
|
||||
try {
|
||||
await fulfillManualLine(props.order.id, line.id);
|
||||
|
||||
ElMessage.success('Line marked as fulfilled.');
|
||||
} catch (error) {
|
||||
const message = resolveAxiosErrorMessage(error, 'Could not mark line as fulfilled.');
|
||||
|
||||
ElMessage.error(message);
|
||||
} finally {
|
||||
fulfillingLineId.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
const resolveLineFulfillmentTag = (line: OrderLine) => {
|
||||
if (props.order.failureReason) {
|
||||
return { label: 'Failed', type: 'danger' as const };
|
||||
}
|
||||
|
||||
if (line.deliveryMode === DeliveryMode.Auto) {
|
||||
return line.autoFulfillmentItems.length > 0
|
||||
? { label: 'Auto-delivered', type: 'success' as const }
|
||||
: { label: 'Pending', type: 'warning' as const };
|
||||
}
|
||||
|
||||
if (isManualLineFulfilled(line)) {
|
||||
return { label: 'Fulfilled', type: 'success' as const };
|
||||
}
|
||||
|
||||
return { label: 'Pending', type: 'warning' as const };
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.order-line-link {
|
||||
color: var(--el-color-primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.order-line-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.order-cart-table :deep(.order-cart-action-col .cell) {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user