💥 Done (almost)
This commit is contained in:
@@ -1,7 +1,12 @@
|
|||||||
|
import { db } from "@pkg/db";
|
||||||
import { Logger } from "@pkg/logger";
|
import { Logger } from "@pkg/logger";
|
||||||
import type { Result } from "@pkg/result";
|
import type { Result } from "@pkg/result";
|
||||||
import type { CreateCustomerInfoPayload, CustomerInfoModel } from "./data";
|
import type {
|
||||||
import type { CustomerInfoRepository } from "./repository";
|
CreateCustomerInfoPayload,
|
||||||
|
CustomerInfoModel,
|
||||||
|
UpdateCustomerInfoPayload,
|
||||||
|
} from "./data";
|
||||||
|
import { CustomerInfoRepository } from "./repository";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CustomerInfoController handles business logic for customer information operations.
|
* CustomerInfoController handles business logic for customer information operations.
|
||||||
@@ -44,6 +49,28 @@ export class CustomerInfoController {
|
|||||||
Logger.info("Retrieving all customer info records");
|
Logger.info("Retrieving all customer info records");
|
||||||
return this.repo.getAllCustomerInfo();
|
return this.repo.getAllCustomerInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates existing customer information
|
||||||
|
* @param payload - Customer information data to update (must include id)
|
||||||
|
* @returns Result containing success boolean or error
|
||||||
|
*/
|
||||||
|
async updateCustomerInfo(
|
||||||
|
payload: UpdateCustomerInfoPayload,
|
||||||
|
): Promise<Result<boolean>> {
|
||||||
|
Logger.info(`Updating customer info with ID: ${payload.id}`);
|
||||||
|
return this.repo.updateCustomerInfo(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes customer information by ID
|
||||||
|
* @param id - Customer info ID to delete
|
||||||
|
* @returns Result containing success boolean or error
|
||||||
|
*/
|
||||||
|
async deleteCustomerInfo(id: number): Promise<Result<boolean>> {
|
||||||
|
Logger.info(`Deleting customer info with ID: ${id}`);
|
||||||
|
return this.repo.deleteCustomerInfo(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCustomerInfoController() {
|
export function getCustomerInfoController() {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { SessionOutcome } from "$lib/domains/ckflow/data/entities";
|
import { SessionOutcome } from "$lib/domains/ckflow/data/entities";
|
||||||
import { getCKUseCases } from "$lib/domains/ckflow/domain/usecases";
|
import { getCKUseCases } from "$lib/domains/ckflow/domain/usecases";
|
||||||
import { getCustomerInfoController } from "$lib/domains/customerinfo/controller";
|
import { getCustomerInfoController } from "$lib/domains/customerinfo/controller";
|
||||||
import { EmailerUseCases } from "$lib/domains/email/domain/usecases";
|
|
||||||
import {
|
import {
|
||||||
CheckoutStep,
|
|
||||||
createOrderPayloadModel,
|
createOrderPayloadModel,
|
||||||
|
OrderCreationStep,
|
||||||
} from "$lib/domains/order/data/entities";
|
} from "$lib/domains/order/data/entities";
|
||||||
import { PaymentInfoRepository } from "$lib/domains/paymentinfo/data/repository";
|
import { PaymentInfoRepository } from "$lib/domains/paymentinfo/data/repository";
|
||||||
import { PaymentInfoUseCases } from "$lib/domains/paymentinfo/domain/usecases";
|
import { PaymentInfoUseCases } from "$lib/domains/paymentinfo/domain/usecases";
|
||||||
@@ -12,66 +11,104 @@ import { getProductUseCases } from "$lib/domains/product/usecases";
|
|||||||
import { createTRPCRouter, publicProcedure } from "$lib/trpc/t";
|
import { createTRPCRouter, publicProcedure } from "$lib/trpc/t";
|
||||||
import { db } from "@pkg/db";
|
import { db } from "@pkg/db";
|
||||||
import { getError, Logger } from "@pkg/logger";
|
import { getError, Logger } from "@pkg/logger";
|
||||||
import { ERROR_CODES } from "@pkg/result";
|
import { ERROR_CODES, type Result } from "@pkg/result";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { OrderRepository } from "../data/repository";
|
import { OrderRepository } from "../data/repository";
|
||||||
import { OrderController } from "./controller";
|
import { OrderController } from "./controller";
|
||||||
|
|
||||||
export const orderRouter = createTRPCRouter({
|
export const orderRouter = createTRPCRouter({
|
||||||
|
/**
|
||||||
|
* Creates a new order for product checkout
|
||||||
|
* Handles customer info creation, payment info creation, and order creation
|
||||||
|
*/
|
||||||
createOrder: publicProcedure
|
createOrder: publicProcedure
|
||||||
.input(createOrderPayloadModel)
|
.input(createOrderPayloadModel)
|
||||||
.mutation(async ({ input }) => {
|
.mutation(async ({ input }) => {
|
||||||
const pduc = new PaymentInfoUseCases(new PaymentInfoRepository(db));
|
const paymentInfoUC = new PaymentInfoUseCases(
|
||||||
const oc = new OrderController(new OrderRepository(db));
|
new PaymentInfoRepository(db),
|
||||||
const cc = getCustomerInfoController();
|
);
|
||||||
const puc = getProductUseCases();
|
const orderController = new OrderController(new OrderRepository(db));
|
||||||
const emailUC = new EmailerUseCases();
|
const customerInfoController = getCustomerInfoController();
|
||||||
|
const productUC = getProductUseCases();
|
||||||
|
|
||||||
const ftRes = await tc.uncacheAndSaveTicket(input.flightTicketId!);
|
// Validate required inputs
|
||||||
if (ftRes.error || !ftRes.data) {
|
if (!input.productId || !input.customerInfo) {
|
||||||
return { error: ftRes.error };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!input.flightTicketId || !input.paymentInfo) {
|
|
||||||
return {
|
return {
|
||||||
error: getError({
|
error: getError({
|
||||||
code: ERROR_CODES.INPUT_ERROR,
|
code: ERROR_CODES.INPUT_ERROR,
|
||||||
message: "Received invalid input",
|
message: "Missing required order information",
|
||||||
detail: "The entered data is incomplete or invalid",
|
detail: "Product ID and customer information are required",
|
||||||
userHint: "Enter valid order data to complete the order",
|
userHint:
|
||||||
|
"Please ensure product and customer information are provided",
|
||||||
}),
|
}),
|
||||||
};
|
} as Result<string>;
|
||||||
}
|
|
||||||
const pdRes = await pduc.createPaymentInfo(input.paymentInfo!);
|
|
||||||
if (pdRes.error || !pdRes.data) {
|
|
||||||
return { error: pdRes.error };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.info(`Setting flight ticket info id ${ftRes.data}`);
|
// Verify product exists
|
||||||
input.orderModel.flightTicketInfoId = ftRes.data;
|
Logger.info(`Verifying product with ID: ${input.productId}`);
|
||||||
|
const productRes = await productUC.getProductById(input.productId);
|
||||||
Logger.info(`Setting payment details id ${pdRes.data}`);
|
if (productRes.error || !productRes.data) {
|
||||||
input.orderModel.paymentInfoId = pdRes.data;
|
return {
|
||||||
|
error: getError({
|
||||||
Logger.info("Creating order");
|
code: ERROR_CODES.NOT_FOUND_ERROR,
|
||||||
const out = await oc.createOrder(input.orderModel);
|
message: "Product not found",
|
||||||
if (out.error || !out.data) {
|
detail: `Product with ID ${input.productId} does not exist`,
|
||||||
await pduc.deletePaymentInfo(pdRes.data!);
|
userHint: "Please select a valid product",
|
||||||
return { error: out.error };
|
}),
|
||||||
|
} as Result<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.info(`Creating customer infos with oid: ${out.data}`);
|
// Create customer information
|
||||||
const pOut = await pc.createPassengerInfos(
|
Logger.info("Creating customer information");
|
||||||
input.passengerInfos,
|
const customerRes = await customerInfoController.createCustomerInfo(
|
||||||
out.data.id,
|
input.customerInfo,
|
||||||
ftRes.data!,
|
|
||||||
pdRes.data,
|
|
||||||
);
|
);
|
||||||
if (pOut.error) {
|
if (customerRes.error || !customerRes.data) {
|
||||||
await oc.deleteOrder(out.data.id);
|
return { error: customerRes.error } as Result<string>;
|
||||||
return { error: pOut.error };
|
}
|
||||||
|
const customerInfoId = customerRes.data;
|
||||||
|
Logger.info(`Customer info created with ID: ${customerInfoId}`);
|
||||||
|
|
||||||
|
// Create payment information if provided
|
||||||
|
let paymentInfoId: number | undefined = undefined;
|
||||||
|
if (input.paymentInfo) {
|
||||||
|
Logger.info("Creating payment information");
|
||||||
|
const paymentRes = await paymentInfoUC.createPaymentInfo(
|
||||||
|
input.paymentInfo,
|
||||||
|
);
|
||||||
|
if (paymentRes.error || !paymentRes.data) {
|
||||||
|
// Cleanup customer info on payment failure
|
||||||
|
await customerInfoController.deleteCustomerInfo(
|
||||||
|
customerInfoId,
|
||||||
|
);
|
||||||
|
return { error: paymentRes.error } as Result<string>;
|
||||||
|
}
|
||||||
|
paymentInfoId = paymentRes.data;
|
||||||
|
Logger.info(`Payment info created with ID: ${paymentInfoId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set IDs in order model
|
||||||
|
input.orderModel.productId = input.productId;
|
||||||
|
input.orderModel.customerInfoId = customerInfoId;
|
||||||
|
input.orderModel.paymentInfoId = paymentInfoId;
|
||||||
|
|
||||||
|
// Create the order
|
||||||
|
Logger.info("Creating order");
|
||||||
|
const orderRes = await orderController.createOrder(input.orderModel);
|
||||||
|
if (orderRes.error || !orderRes.data) {
|
||||||
|
// Cleanup on order creation failure
|
||||||
|
if (paymentInfoId) {
|
||||||
|
await paymentInfoUC.deletePaymentInfo(paymentInfoId);
|
||||||
|
}
|
||||||
|
await customerInfoController.deleteCustomerInfo(customerInfoId);
|
||||||
|
return { error: orderRes.error } as Result<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderId = orderRes.data.id;
|
||||||
|
const orderUID = orderRes.data.uid;
|
||||||
|
Logger.info(`Order created successfully with ID: ${orderId}`);
|
||||||
|
|
||||||
|
// Update checkout flow state if flowId is provided
|
||||||
if (input.flowId) {
|
if (input.flowId) {
|
||||||
Logger.info(
|
Logger.info(
|
||||||
`Updating checkout flow state for flow ${input.flowId}`,
|
`Updating checkout flow state for flow ${input.flowId}`,
|
||||||
@@ -79,7 +116,7 @@ export const orderRouter = createTRPCRouter({
|
|||||||
try {
|
try {
|
||||||
await getCKUseCases().cleanupFlow(input.flowId, {
|
await getCKUseCases().cleanupFlow(input.flowId, {
|
||||||
sessionOutcome: SessionOutcome.COMPLETED,
|
sessionOutcome: SessionOutcome.COMPLETED,
|
||||||
checkoutStep: CheckoutStep.Complete,
|
checkoutStep: OrderCreationStep.SUMMARY,
|
||||||
});
|
});
|
||||||
Logger.info(
|
Logger.info(
|
||||||
`Checkout flow ${input.flowId} marked as completed`,
|
`Checkout flow ${input.flowId} marked as completed`,
|
||||||
@@ -90,94 +127,29 @@ export const orderRouter = createTRPCRouter({
|
|||||||
);
|
);
|
||||||
Logger.error(err);
|
Logger.error(err);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Logger.warn(
|
|
||||||
`No flow id found to mark as completed: ${input.flowId}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const uid = out.data.uid;
|
Logger.debug(
|
||||||
|
"Rotating the link id for the product now that it's been used",
|
||||||
if (!uid) {
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// Get order details for email
|
|
||||||
const orderDetails = await oc.getOrderByPNR(uid);
|
|
||||||
|
|
||||||
if (!orderDetails.data) {
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
const order = orderDetails.data;
|
|
||||||
const ticketInfo = order.flightTicketInfo;
|
|
||||||
const primaryPassenger = order.passengerInfos[0]?.passengerPii!;
|
|
||||||
|
|
||||||
if (!ticketInfo || !primaryPassenger) {
|
|
||||||
Logger.warn(
|
|
||||||
`No email address found for passenger to send PNR confirmation`,
|
|
||||||
);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
// Get passenger email address to send confirmation to
|
|
||||||
const passengerEmail = primaryPassenger.email;
|
|
||||||
if (!passengerEmail) {
|
|
||||||
Logger.warn(
|
|
||||||
`No email address found for passenger to send PNR confirmation`,
|
|
||||||
);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
Logger.info(
|
|
||||||
`Sending PNR confirmation email to ${passengerEmail}`,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Send the email with React component directly
|
const out = await productUC.refreshProductLinkId(input.productId);
|
||||||
const emailResult = await emailUC.sendEmailWithTemplate({
|
|
||||||
to: passengerEmail,
|
|
||||||
subject: `Flight Confirmation: ${ticketInfo.departure} to ${ticketInfo.arrival} - PNR: ${uid}`,
|
|
||||||
template: "uid-confirmation",
|
|
||||||
templateData: {
|
|
||||||
uid: uid,
|
|
||||||
origin: ticketInfo.departure,
|
|
||||||
destination: ticketInfo.arrival,
|
|
||||||
departureDate: new Date(
|
|
||||||
ticketInfo.departureDate,
|
|
||||||
).toISOString(),
|
|
||||||
returnDate: new Date(
|
|
||||||
ticketInfo.returnDate,
|
|
||||||
)?.toISOString(),
|
|
||||||
passengerName: `${primaryPassenger.firstName}`,
|
|
||||||
baseUrl: "https://FlyTicketTravel.com",
|
|
||||||
logoPath:
|
|
||||||
"https://FlyTicketTravel.com/assets/logos/logo-main.svg",
|
|
||||||
companyName: "FlyTicketTravel",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (emailResult.error) {
|
Logger.debug(
|
||||||
Logger.error(
|
`Product link id rotated: ${JSON.stringify(out, null, 2)}`,
|
||||||
`Failed to send PNR confirmation email: ${emailResult.error.message}`,
|
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
Logger.info(
|
|
||||||
`PNR confirmation email sent to ${passengerEmail}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (emailError) {
|
|
||||||
// Don't fail the order if email sending fails
|
|
||||||
Logger.error(
|
|
||||||
`Error sending PNR confirmation email: ${emailError}`,
|
|
||||||
);
|
|
||||||
Logger.error(emailError);
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.info("Done with order creation, returning");
|
Logger.info("Order creation completed successfully");
|
||||||
return out;
|
return { data: orderUID } as Result<string>;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
findByUID: publicProcedure
|
/**
|
||||||
|
* Finds an order by its ID
|
||||||
|
*/
|
||||||
|
findByIdUID: publicProcedure
|
||||||
.input(z.object({ uid: z.string() }))
|
.input(z.object({ uid: z.string() }))
|
||||||
.query(async ({ input }) => {
|
.query(async ({ input }) => {
|
||||||
const oc = new OrderController(new OrderRepository(db));
|
const orderController = new OrderController(new OrderRepository(db));
|
||||||
return oc.getOrderByUID(input.uid);
|
return orderController.getOrderByUID(input.uid);
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -119,8 +119,6 @@ export class CreateOrderViewModel {
|
|||||||
orderModel: {
|
orderModel: {
|
||||||
...priceDetails,
|
...priceDetails,
|
||||||
productId: product.id,
|
productId: product.id,
|
||||||
customerInfoId: customerInfoVM.customerInfo.id,
|
|
||||||
paymentInfoId: undefined,
|
|
||||||
},
|
},
|
||||||
flowId: ckFlowVM.flowId,
|
flowId: ckFlowVM.flowId,
|
||||||
});
|
});
|
||||||
@@ -160,7 +158,7 @@ export class CreateOrderViewModel {
|
|||||||
|
|
||||||
// Redirect to success page after a short delay
|
// Redirect to success page after a short delay
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.href = `/order/success?id=${out.data}`;
|
window.location.href = `/order/success?uid=${out.data}`;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
description: "Preparing checkout session",
|
description: "Preparing checkout session",
|
||||||
});
|
});
|
||||||
window.location.replace(
|
window.location.replace(
|
||||||
`/checkout/${$checkoutSessionIdStore}/${data.data.id}`,
|
`/checkout/${$checkoutSessionIdStore}/${data.data.linkId}`,
|
||||||
);
|
);
|
||||||
}, 3000);
|
}, 3000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,5 @@ import { getProductUseCases } from "$lib/domains/product/usecases";
|
|||||||
import type { PageServerLoad } from "./$types";
|
import type { PageServerLoad } from "./$types";
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ params }) => {
|
export const load: PageServerLoad = async ({ params }) => {
|
||||||
return await getProductUseCases().getProductByLinkId(
|
return await getProductUseCases().getProductByLinkId(params.plid);
|
||||||
Number(params.plid ?? "-1"),
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import Icon from "$lib/components/atoms/icon.svelte";
|
import Icon from "$lib/components/atoms/icon.svelte";
|
||||||
import Title from "$lib/components/atoms/title.svelte";
|
import Title from "$lib/components/atoms/title.svelte";
|
||||||
import MaxWidthWrapper from "$lib/components/molecules/max-width-wrapper.svelte";
|
import MaxWidthWrapper from "$lib/components/molecules/max-width-wrapper.svelte";
|
||||||
import Button from "$lib/components/ui/button/button.svelte";
|
|
||||||
import CheckoutConfirmationSection from "$lib/domains/checkout/checkout-confirmation-section.svelte";
|
import CheckoutConfirmationSection from "$lib/domains/checkout/checkout-confirmation-section.svelte";
|
||||||
import CheckoutLoadingSection from "$lib/domains/checkout/checkout-loading-section.svelte";
|
import CheckoutLoadingSection from "$lib/domains/checkout/checkout-loading-section.svelte";
|
||||||
import CheckoutStepsIndicator from "$lib/domains/checkout/checkout-steps-indicator.svelte";
|
import CheckoutStepsIndicator from "$lib/domains/checkout/checkout-steps-indicator.svelte";
|
||||||
@@ -51,10 +50,8 @@
|
|||||||
<div class="grid h-full min-h-screen w-full place-items-center">
|
<div class="grid h-full min-h-screen w-full place-items-center">
|
||||||
<div class="flex flex-col items-center justify-center gap-4">
|
<div class="flex flex-col items-center justify-center gap-4">
|
||||||
<Icon icon={SearchIcon} cls="w-12 h-12" />
|
<Icon icon={SearchIcon} cls="w-12 h-12" />
|
||||||
<Title size="h4" color="black">No ticket found</Title>
|
<Title size="h4" color="black">Product not found</Title>
|
||||||
<Button href="/search" variant="default">
|
<p>Something went wrong, please try again or contact us</p>
|
||||||
Search for another ticket
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else if checkoutVM.checkoutStep === CheckoutStep.Confirmation}
|
{:else if checkoutVM.checkoutStep === CheckoutStep.Confirmation}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import Title from "$lib/components/atoms/title.svelte";
|
import Title from "$lib/components/atoms/title.svelte";
|
||||||
import MaxWidthWrapper from "$lib/components/molecules/max-width-wrapper.svelte";
|
import MaxWidthWrapper from "$lib/components/molecules/max-width-wrapper.svelte";
|
||||||
import CheckIcon from "~icons/ic/round-check";
|
import CheckIcon from "~icons/ic/round-check";
|
||||||
|
// Maybe todo? if the `uid` search param is present, do something?? figure out later
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="grid min-h-[80vh] w-full place-items-center px-4 sm:px-6">
|
<div class="grid min-h-[80vh] w-full place-items-center px-4 sm:px-6">
|
||||||
|
|||||||
@@ -3,11 +3,8 @@
|
|||||||
import Icon from "$lib/components/atoms/icon.svelte";
|
import Icon from "$lib/components/atoms/icon.svelte";
|
||||||
import Title from "$lib/components/atoms/title.svelte";
|
import Title from "$lib/components/atoms/title.svelte";
|
||||||
import MaxWidthWrapper from "$lib/components/molecules/max-width-wrapper.svelte";
|
import MaxWidthWrapper from "$lib/components/molecules/max-width-wrapper.svelte";
|
||||||
import Button from "$lib/components/ui/button/button.svelte";
|
|
||||||
import CloseIcon from "~icons/mdi/window-close";
|
|
||||||
import ArrowRightIcon from "~icons/solar/multiple-forward-right-line-duotone";
|
|
||||||
import RestartIcon from "~icons/material-symbols/restart-alt-rounded";
|
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
import CloseIcon from "~icons/mdi/window-close";
|
||||||
|
|
||||||
let canRedirect = $state(false);
|
let canRedirect = $state(false);
|
||||||
|
|
||||||
@@ -37,25 +34,9 @@
|
|||||||
<Title size="h3" center weight="medium">Session Terminated</Title>
|
<Title size="h3" center weight="medium">Session Terminated</Title>
|
||||||
<p class="w-full max-w-prose text-center text-gray-600">
|
<p class="w-full max-w-prose text-center text-gray-600">
|
||||||
Unfortunately, your session has been terminated due to inactivity
|
Unfortunately, your session has been terminated due to inactivity
|
||||||
or expiration of the booking.
|
or something went wrong, please contact us to walk through the
|
||||||
|
steps again.
|
||||||
</p>
|
</p>
|
||||||
<div class="flex w-full flex-col justify-center gap-4 md:flex-row">
|
|
||||||
{#if canRedirect}
|
|
||||||
<Button
|
|
||||||
variant="default"
|
|
||||||
size="lg"
|
|
||||||
href={`/checkout/${sid}/${tid}`}
|
|
||||||
>
|
|
||||||
<Icon icon={RestartIcon} cls="w-auto h-6" />
|
|
||||||
<span>Try Again</span>
|
|
||||||
</Button>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<Button variant="defaultInverted" size="lg" href="/search">
|
|
||||||
<Icon icon={ArrowRightIcon} cls="w-auto h-6" />
|
|
||||||
<span>Back To Search</span>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</MaxWidthWrapper>
|
</MaxWidthWrapper>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -102,7 +102,8 @@ export function getDefaultPaginatedOrderInfoModel(): PaginatedOrderInfoModel {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const newOrderModel = orderModel.pick({
|
export const newOrderModel = orderModel
|
||||||
|
.pick({
|
||||||
basePrice: true,
|
basePrice: true,
|
||||||
displayPrice: true,
|
displayPrice: true,
|
||||||
discountAmount: true,
|
discountAmount: true,
|
||||||
@@ -111,7 +112,12 @@ export const newOrderModel = orderModel.pick({
|
|||||||
productId: true,
|
productId: true,
|
||||||
customerInfoId: true,
|
customerInfoId: true,
|
||||||
paymentInfoId: true,
|
paymentInfoId: true,
|
||||||
});
|
})
|
||||||
|
.extend({
|
||||||
|
currency: z.string().default("USD"),
|
||||||
|
customerInfoId: z.number().optional(),
|
||||||
|
paymentInfoId: z.number().optional(),
|
||||||
|
});
|
||||||
export type NewOrderModel = z.infer<typeof newOrderModel>;
|
export type NewOrderModel = z.infer<typeof newOrderModel>;
|
||||||
|
|
||||||
export const createOrderPayloadModel = z.object({
|
export const createOrderPayloadModel = z.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user