@heyframe/composables
Version:
HeyFrame Frontends composables for Vue
317 lines (292 loc) • 8.44 kB
text/typescript
import { defu } from "defu";
import { computed, inject, provide, ref } from "vue";
import type { ComputedRef, Ref } from "vue";
import { useDefaultOrderAssociations, useHeyFrameContext } from "#imports";
import type { Schemas, operations } from "#heyframe";
export type UseOrderDetailsReturn = {
/**
* {@link Schemas['Order']} object
*/
order: ComputedRef<Schemas["Order"] | undefined | null>;
/**
* Order status (e.g. 'Open', 'Cancelled')
*/
status: ComputedRef<string | undefined>;
/**
* Order status technical name (e.g. 'open', 'cancelled')
*/
statusTechnicalName: ComputedRef<string | undefined>;
/**
* Order total price
*/
total: ComputedRef<number | undefined>;
/**
* Order subtotal price for all items
*/
subtotal: ComputedRef<number | undefined>;
/**
* Order shipping costs
*/
shippingCosts: ComputedRef<number | undefined>;
/**
* Shipping address
*/
shippingAddress: ComputedRef<Schemas["OrderAddress"] | undefined>;
/**
* Billing address
*/
billingAddress: ComputedRef<Schemas["OrderAddress"] | undefined>;
/**
* Basic personal details
*/
personalDetails: ComputedRef<{
email: string | undefined;
firstName: string | undefined;
lastName: string | undefined;
}>;
/**
* Payment URL for external payment methods (e.g. async payment in external payment gateway)
*/
paymentUrl: Ref<null | string>;
/**
* Returns current selected shipping method for the order. Last element in delivery array.
*/
shippingMethod: ComputedRef<Schemas["ShippingMethod"] | undefined | null>;
/**
* Returns current selected payment method for the order. Last element in transactions array.
*/
paymentMethod: ComputedRef<Schemas["PaymentMethod"] | undefined | null>;
/**
* Get order object including additional associations.
* useDefaults describes what order object should look like.
*/
loadOrderDetails(): Promise<Schemas["OrderRouteResponse"]>;
/**
* Handle payment for existing error.
*
* Pass custom success and error URLs (optionally).
*/
handlePayment(
successUrl?: string,
errorUrl?: string,
paymentDetails?: unknown,
): void;
/**
* Cancel an order.
*
* Action cannot be reverted.
*/
cancel(): Promise<Schemas["StateMachineState"]>;
/**
* Changes the payment method for current cart.
* @param paymentMethodId - ID of the payment method to be set
* @returns
*/
changePaymentMethod(
paymentMethodId: string,
): Promise<Schemas["SuccessResponse"]>;
/**
* Get media content
*
* @param {string} downloadId
* @returns {Blob}
*/
getMediaFile: (downloadId: string) => Promise<Blob>;
/**
* Get order documents
* @param {string} documentId
* @param {string} deepLinkCode
* @returns
*/
getDocumentFile: (
documentId: string,
deepLinkCode: string,
) => Promise<Schemas["Document"]>;
/**
* Check if order has documents
*/
hasDocuments: ComputedRef<boolean>;
/**
* Get order documents
*/
documents: ComputedRef<Schemas["Document"][]>;
/**
* Fetches all available payment methods
*/
getPaymentMethods(): Promise<Schemas["PaymentMethod"][]>;
paymentChangeable: ComputedRef<boolean>;
};
/**
* Composable for managing an existing order.
* @public
* @category Customer & Account
*/
export function useOrderDetails(
orderId: string,
associations?: Schemas["Criteria"]["associations"],
): UseOrderDetailsReturn {
const { apiClient } = useHeyFrameContext();
const paymentChangeableList: Ref<{ [key: string]: boolean }> = ref({});
const _sharedOrder = inject<Ref<Schemas["Order"] | undefined>>(
"swOrderDetails",
ref(),
);
provide("swOrderDetails", _sharedOrder);
const orderAssociations = useDefaultOrderAssociations();
const paymentMethod = computed(() => {
const transactions = _sharedOrder.value?.transactions;
if (!transactions?.length) return undefined;
return transactions[transactions.length - 1]?.paymentMethod;
});
const shippingMethod = computed(() => {
const deliveries = _sharedOrder.value?.deliveries;
if (!deliveries?.length) return undefined;
return deliveries[deliveries.length - 1]?.shippingMethod;
});
const paymentUrl = ref();
const personalDetails = computed(() => ({
email: _sharedOrder.value?.orderCustomer?.email,
firstName: _sharedOrder.value?.orderCustomer?.firstName,
lastName: _sharedOrder.value?.orderCustomer?.lastName,
}));
const billingAddress = computed(() =>
_sharedOrder.value?.addresses?.find(
({ id }: { id: string }) => id === _sharedOrder.value?.billingAddressId,
),
);
const shippingAddress = computed(
() => _sharedOrder.value?.deliveries?.[0]?.shippingOrderAddress,
);
const shippingCosts = computed(() => _sharedOrder.value?.shippingTotal);
const subtotal = computed(() => _sharedOrder.value?.price?.positionPrice);
const total = computed(() => _sharedOrder.value?.price?.totalPrice);
const status = computed(
() => _sharedOrder.value?.stateMachineState?.translated.name,
);
const statusTechnicalName = computed(
() => _sharedOrder.value?.stateMachineState?.technicalName,
);
async function loadOrderDetails() {
const mergedAssociations = defu(
orderAssociations,
associations ? associations : {},
);
const params: operations["readOrder post /order"]["body"] = {
ids: [orderId],
associations: mergedAssociations,
checkPromotion: true,
};
const orderDetailsResponse = await apiClient.invoke(
"readOrder post /order",
{
body: params,
},
);
_sharedOrder.value =
orderDetailsResponse.data.orders?.elements?.[0] ?? undefined;
paymentChangeableList.value =
orderDetailsResponse.data.paymentChangeable ?? {};
return orderDetailsResponse.data;
}
async function handlePayment(finishUrl?: string, errorUrl?: string) {
const resp = await apiClient.invoke(
"handlePaymentMethod post /handle-payment",
{
body: {
orderId,
finishUrl,
errorUrl,
},
},
);
paymentUrl.value = resp.data.redirectUrl;
}
async function cancel() {
const resp = await apiClient.invoke(
"cancelOrder post /order/state/cancel",
{
body: {
orderId,
},
},
);
await loadOrderDetails();
return resp.data;
}
async function changePaymentMethod(paymentMethodId: string) {
const response = await apiClient.invoke(
"orderSetPayment post /order/payment",
{
body: {
orderId: orderId,
paymentMethodId: paymentMethodId,
},
},
);
await loadOrderDetails();
return response.data;
}
async function getMediaFile(downloadId: string) {
const response = await apiClient.invoke(
"orderDownloadFile get /order/download/{orderId}/{downloadId}",
{
accept: "application/octet-stream",
pathParams: {
orderId,
downloadId,
},
},
);
return response.data;
}
async function getDocumentFile(documentId: string, deepLinkCode: string) {
const response = await apiClient.invoke(
"download post /document/download/{documentId}/{deepLinkCode}",
{
pathParams: {
documentId,
deepLinkCode,
},
},
);
return response.data;
}
const hasDocuments = computed(() => !!_sharedOrder.value?.documents.length);
const documents = computed(() => _sharedOrder.value?.documents || []);
const paymentChangeable = computed(() => {
return paymentChangeableList.value?.[orderId as string] ?? false;
});
const getPaymentMethods = async () => {
const response = await apiClient.invoke(
"readPaymentMethod post /payment-method",
{
body: { onlyAvailable: true },
},
);
return response.data.elements || [];
};
return {
order: computed(() => _sharedOrder.value),
status,
statusTechnicalName,
total,
subtotal,
shippingCosts,
shippingAddress,
billingAddress,
personalDetails,
paymentUrl,
shippingMethod,
paymentMethod,
hasDocuments,
documents,
loadOrderDetails,
handlePayment,
cancel,
changePaymentMethod,
getMediaFile,
getDocumentFile,
paymentChangeable,
getPaymentMethods,
};
}