167 lines
4.2 KiB
TypeScript
167 lines
4.2 KiB
TypeScript
import { ckFlowVM } from "$lib/domains/ckflow/view/ckflow.vm.svelte";
|
|
import { newOrderModel } from "$lib/domains/order/data/entities";
|
|
import { passengerInfoVM } from "$lib/domains/passengerinfo/view/passenger.info.vm.svelte";
|
|
import {
|
|
paymentInfoPayloadModel,
|
|
PaymentMethod,
|
|
} from "$lib/domains/paymentinfo/data/entities";
|
|
import { trpcApiStore } from "$lib/stores/api";
|
|
import { toast } from "svelte-sonner";
|
|
import { get } from "svelte/store";
|
|
import { CheckoutStep } from "../../data/entities/index";
|
|
import { flightTicketStore } from "../../data/store";
|
|
import { paymentInfoVM } from "./payment-info-section/payment.info.vm.svelte";
|
|
import { calculateTicketPrices } from "./total.calculator";
|
|
|
|
class TicketCheckoutViewModel {
|
|
checkoutStep = $state(CheckoutStep.Initial);
|
|
loading = $state(true);
|
|
continutingToNextStep = $state(false);
|
|
|
|
checkoutSubmitted = $state(false);
|
|
|
|
livenessPinger: NodeJS.Timer | undefined = $state(undefined);
|
|
|
|
reset() {
|
|
this.checkoutStep = CheckoutStep.Initial;
|
|
this.resetPinger();
|
|
}
|
|
|
|
setupPinger() {
|
|
this.resetPinger();
|
|
this.livenessPinger = setInterval(() => {
|
|
this.ping();
|
|
}, 5_000);
|
|
}
|
|
|
|
resetPinger() {
|
|
if (this.livenessPinger) {
|
|
clearInterval(this.livenessPinger);
|
|
}
|
|
}
|
|
|
|
private async ping() {
|
|
const api = get(trpcApiStore);
|
|
if (!api) {
|
|
return false;
|
|
}
|
|
const ticket = get(flightTicketStore);
|
|
if (!ticket || !ticket.refOIds) {
|
|
return false;
|
|
}
|
|
const out = await api.ticket.ping.query({
|
|
tid: ticket.id,
|
|
refOIds: ticket.refOIds,
|
|
});
|
|
}
|
|
|
|
async checkout() {
|
|
if (this.checkoutSubmitted || this.loading) {
|
|
return;
|
|
}
|
|
this.checkoutSubmitted = true;
|
|
|
|
const api = get(trpcApiStore);
|
|
if (!api) {
|
|
this.checkoutSubmitted = false;
|
|
return false;
|
|
}
|
|
|
|
const ticket = get(flightTicketStore);
|
|
|
|
const prices = calculateTicketPrices(
|
|
ticket,
|
|
passengerInfoVM.passengerInfos,
|
|
);
|
|
|
|
const validatedPrices = {
|
|
subtotal: isNaN(prices.subtotal) ? 0 : prices.subtotal,
|
|
discountAmount: isNaN(prices.discountAmount)
|
|
? 0
|
|
: prices.discountAmount,
|
|
finalTotal: isNaN(prices.finalTotal) ? 0 : prices.finalTotal,
|
|
pricePerPassenger: isNaN(prices.pricePerPassenger)
|
|
? 0
|
|
: prices.pricePerPassenger,
|
|
};
|
|
|
|
const parsed = newOrderModel.safeParse({
|
|
basePrice: validatedPrices.subtotal,
|
|
discountAmount: validatedPrices.discountAmount,
|
|
displayPrice: validatedPrices.finalTotal,
|
|
orderPrice: validatedPrices.finalTotal, // Same as displayPrice
|
|
fullfilledPrice: validatedPrices.finalTotal, // Same as displayPrice
|
|
pricePerPassenger: validatedPrices.pricePerPassenger,
|
|
flightTicketInfoId: -1,
|
|
paymentInfoId: -1,
|
|
});
|
|
|
|
if (parsed.error) {
|
|
console.log(parsed.error);
|
|
const err = parsed.error.errors[0];
|
|
toast.error("Failed to perform checkout", {
|
|
description: err.message,
|
|
});
|
|
return false;
|
|
}
|
|
|
|
const pInfoParsed = paymentInfoPayloadModel.safeParse({
|
|
method: PaymentMethod.Card,
|
|
cardDetails: paymentInfoVM.cardDetails,
|
|
flightTicketInfoId: ticket.id,
|
|
});
|
|
if (pInfoParsed.error) {
|
|
console.log(parsed.error);
|
|
const err = pInfoParsed.error.errors[0];
|
|
toast.error("Failed to perform checkout", {
|
|
description: err.message,
|
|
});
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
console.log("Creating order");
|
|
this.loading = true;
|
|
const out = await api.order.createOrder.mutate({
|
|
flightTicketId: ticket.id,
|
|
orderModel: parsed.data,
|
|
passengerInfos: passengerInfoVM.passengerInfos,
|
|
paymentInfo: pInfoParsed.data,
|
|
refOIds: ticket.refOIds,
|
|
flowId: ckFlowVM.flowId,
|
|
});
|
|
|
|
if (out.error) {
|
|
this.loading = false;
|
|
toast.error(out.error.message, {
|
|
description: out.error.userHint,
|
|
});
|
|
return false;
|
|
}
|
|
if (!out.data) {
|
|
this.loading = false;
|
|
toast.error("Failed to create order", {
|
|
description: "Please try again",
|
|
});
|
|
return false;
|
|
}
|
|
|
|
toast.success("Order created successfully", {
|
|
description: "Redirecting, please wait...",
|
|
});
|
|
setTimeout(() => {
|
|
window.location.href = `/checkout/success?oid=${out.data}`;
|
|
}, 500);
|
|
return true;
|
|
} catch (e) {
|
|
this.checkoutSubmitted = false;
|
|
toast.error("An error occurred during checkout", {
|
|
description: "Please try again",
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
export const ticketCheckoutVM = new TicketCheckoutViewModel();
|