From ca54608919a856e2aad7ecb35f4509701db1f01c Mon Sep 17 00:00:00 2001 From: limivann <71662324+limivann@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:30:33 +0800 Subject: [PATCH 1/4] feat(merch): Config to use mongodb --- apps/merch/package.json | 1 + apps/merch/src/db/mongodb.ts | 65 +++++++++++++ apps/merch/src/db/orders.ts | 121 +++++++++++------------- apps/merch/src/index.ts | 12 ++- apps/merch/src/models/Order.ts | 22 +++++ apps/merch/src/models/OrderItem.ts | 16 ++++ apps/merch/src/routes/checkout.ts | 19 ++-- apps/merch/src/routes/orders.ts | 6 +- apps/web/features/merch/services/api.ts | 6 +- packages/merch-helpers/src/lib/price.ts | 4 +- packages/types/src/lib/merch.ts | 8 +- yarn.lock | 83 +++++++++++++++- 12 files changed, 273 insertions(+), 90 deletions(-) create mode 100644 apps/merch/src/db/mongodb.ts create mode 100644 apps/merch/src/models/Order.ts create mode 100644 apps/merch/src/models/OrderItem.ts diff --git a/apps/merch/package.json b/apps/merch/package.json index c8d65a02..6cc6f35f 100644 --- a/apps/merch/package.json +++ b/apps/merch/package.json @@ -24,6 +24,7 @@ "dotenv": "^16.3.1", "express": "^4.19.2", "merch-helpers": "*", + "mongoose": "^8.6.1", "nodelogger": "*", "stripe": "^12.5.0", "trpc-panel": "^1.3.4", diff --git a/apps/merch/src/db/mongodb.ts b/apps/merch/src/db/mongodb.ts new file mode 100644 index 00000000..1bbdef8a --- /dev/null +++ b/apps/merch/src/db/mongodb.ts @@ -0,0 +1,65 @@ +import mongoose, { Model, Document, FilterQuery } from "mongoose"; +import { Logger } from "nodelogger"; + +export class NotFoundError { + message: string; + constructor(item = "") { + this.message = "Item " + item + " not found."; + } +} + +export class ItemExistError { + message: string; + constructor(id = "") { + this.message = "Item with " + id + " already exists."; + } +} + +// readTable scans the table for all entries +export const readTable = async(model: Model): Promise => { + const response = await model.find().exec(); + if (!response) { + return []; + } + return response as T[]; +}; + +// readItem retrieves the specified item from the table. +export const readItem = async ( + model: Model, + key: string, + keyId = "id" +): Promise => { + const query: FilterQuery = { [keyId]: key } as FilterQuery; + const response = await model.findOne(query).exec(); + if (!response) { + Logger.warn(`Item does not exist in table ${model.modelName}`); + throw new NotFoundError(key); + } + return response as T; +}; + +// writeItem adds the given item to the specified model table. +export const writeItem = async ( + model: Model, + item: T +): Promise => { + try { + return await model.create(item); + } catch (error) { + const errorMessage = (error as Error).message + Logger.error(`An error occurred: ${errorMessage}`); + return null; + } +}; + +export const setupDb = async (): Promise => { + try { + const mongoDb = process.env.MONGODB_URI ?? ""; + await mongoose.connect(mongoDb); + Logger.info("Database connected successfully"); + } catch (error) { + const errorMessage = (error as Error).message + Logger.error(`Database connection error: ${errorMessage}`); + } +}; \ No newline at end of file diff --git a/apps/merch/src/db/orders.ts b/apps/merch/src/db/orders.ts index edff273b..655e344a 100644 --- a/apps/merch/src/db/orders.ts +++ b/apps/merch/src/db/orders.ts @@ -1,108 +1,94 @@ -import { readItem, writeItem } from "./dynamodb"; -import { v4 as uuidv4 } from "uuid"; -import { Order, OrderItem, OrderStatus, OrderHoldEntry } from "types"; +import { readItem, readTable, writeItem } from "./mongodb"; +import { Order, OrderItem, OrderStatus } from "types"; +import { OrderDocument, OrderModel } from "../models/Order"; -const ORDER_TABLE_NAME = process.env.ORDER_TABLE_NAME; -const ORDER_HOLD_TABLE_NAME = process.env.ORDER_HOLD_TABLE_NAME; - -if (!ORDER_TABLE_NAME) { - throw new Error("ORDER_TABLE_NAME is not defined"); -} -if (!ORDER_HOLD_TABLE_NAME) { - throw new Error("ORDER_HOLD_TABLE_NAME is not defined"); +export interface MongoOrder { + _id: string; + items: MongoOrderItem[]; + transactionId: string; + transactionTime: string | null; + paymentMethod: string; + customerEmail: string; + status: OrderStatus; } -interface DynamoOrderItem { +export interface MongoOrderItem { id: string; - image: string; - quantity: number; + name: string; + image?: string; + color: string; size: string; price: number; - name: string; - colorway: string; - // product_category: string; -} - -interface DynamoOrder { - orderID: string; - paymentGateway: string; - orderItems: DynamoOrderItem[]; - status: OrderStatus; - customerEmail: string; - transactionID: string; - orderDateTime: string; + quantity: number; } -interface DynamoOrderHoldEntry { - // todo +export const getOrders = async (): Promise => { + const orders = await readTable(OrderModel); + // TODO: decode orders + return orders; } -export const getOrder = async (id: string) => { - const dynamoOrder = await readItem( - ORDER_TABLE_NAME ?? "", - id, - "orderID" - ); - return decodeOrder(dynamoOrder); +export const getOrder = async (id: string): Promise => { + const order = await readItem(OrderModel, id, "_id"); + return decodeOrder(order); }; -const decodeOrder = (order: DynamoOrder): Order => { - let date: string | null; - try { - date = new Date(order.orderDateTime).toISOString(); - } catch (e) { - date = null; +export const createOrder = async (order: Order): Promise => { + const mongoOrder = encodeOrder(order); + const newItem = await writeItem(OrderModel, mongoOrder as OrderDocument); + if (!newItem) { + return null; } + return decodeOrder(newItem); +}; + +const decodeOrder = (order: MongoOrder): Order => { + const date = order.transactionTime + ? new Date(order.transactionTime).toISOString() + : new Date().toISOString(); return { - id: order.orderID || "", - payment_method: order.paymentGateway || "", - items: order.orderItems.map((item) => ({ + id: order._id || "", + paymentMethod: order.paymentMethod || "", + items: order.items.map((item: MongoOrderItem) => ({ id: item.id || "", name: item.name || "", - // category: item.product_category || "", image: item.image || undefined, - color: item.colorway || "", + color: item.color || "", size: item.size || "", price: item.price || 0, quantity: item.quantity || 1, })), status: order.status || OrderStatus.PENDING_PAYMENT, - customer_email: order.customerEmail || "", - transaction_id: order.transactionID || "", - transaction_time: date || null, + customerEmail: order.customerEmail || "", + transactionId: order.transactionId || "", + transactionTime: date || null, }; }; -const encodeOrderItem = (item: OrderItem): DynamoOrderItem => ({ +const encodeOrderItem = (item: OrderItem): OrderItem => ({ id: item.id, image: item.image ? item.image : "", quantity: item.quantity, size: item.size, price: item.price, name: item.name, - colorway: item.color, - // product_category: item.category, + color: item.color, }); -const encodeOrder = (order: Order): DynamoOrder => ({ - transactionID: order.transaction_id || "", - orderID: order.id, - paymentGateway: order.payment_method || "", - orderItems: order.items.map(encodeOrderItem), +const encodeOrder = (order: Order): MongoOrder => ({ + transactionId: order.transactionId || "", + _id: order.id, + paymentMethod: order.paymentMethod || "", + items: order.items.map(encodeOrderItem), status: order.status || OrderStatus.PENDING_PAYMENT, - customerEmail: order.customer_email || "", - orderDateTime: order.transaction_time - ? new Date(order.transaction_time).toISOString() + customerEmail: order.customerEmail || "", + transactionTime: order.transactionTime + ? new Date(order.transactionTime).toISOString() : new Date().toISOString(), }); -export const createOrder = async (order: Order): Promise => { - const dynamoOrder = encodeOrder(order); - dynamoOrder.orderID = uuidv4(); - await writeItem(ORDER_TABLE_NAME, dynamoOrder); - return decodeOrder(dynamoOrder); -}; +/* const encodeOrderHoldEntry = ( _orderHoldEntry: OrderHoldEntry ): DynamoOrderHoldEntry => { @@ -117,3 +103,4 @@ export const createOrderHoldEntry = async ( const dynamoOrderHoldEntry = encodeOrderHoldEntry(orderHoldEntry); await writeItem(ORDER_HOLD_TABLE_NAME, dynamoOrderHoldEntry); }; +*/ \ No newline at end of file diff --git a/apps/merch/src/index.ts b/apps/merch/src/index.ts index f8707836..283caa51 100644 --- a/apps/merch/src/index.ts +++ b/apps/merch/src/index.ts @@ -10,6 +10,7 @@ import { index, notFound } from "./routes/index"; import { orderGet } from "./routes/orders"; import { productGet, productsAll } from "./routes/products"; import { appRouter, trpcMiddleware } from "./trpc/router"; +import { setupDb } from "./db/mongodb"; const app = express(); const CORS_ORIGIN = process.env.CORS_ORIGIN; @@ -49,6 +50,13 @@ app.use("/trpc-panel", (_, res) => { app.use(notFound); const port = 3002; -app.listen(port, () => Logger.info(`server started on port ${port}`)); - +app.listen(port, () => { + (async () => { + await setupDb(); + Logger.info(`Server started on port ${port}`); + })().catch((error) => { + const errorMessage = (error as Error).message + Logger.error(`Failed to start server: ${errorMessage}`); + }); +}); export default app; diff --git a/apps/merch/src/models/Order.ts b/apps/merch/src/models/Order.ts new file mode 100644 index 00000000..1f2bbec8 --- /dev/null +++ b/apps/merch/src/models/Order.ts @@ -0,0 +1,22 @@ +import mongoose, { Schema, Document } from "mongoose"; +import { OrderStatus } from "types"; +import { OrderItemSchema } from "./OrderItem"; +import { MongoOrder } from "../db"; + +export type OrderDocument = MongoOrder & Document; + +const OrderSchema: Schema = new Schema({ + _id: { type: String }, + items: [ OrderItemSchema ], + transactionId: { type: String, default: "" }, + transactionTime: { type: String, default: null }, + paymentMethod: { type: String, default: "" }, + customerEmail: { type: String, default: "" }, + status: { + type: Number, + enum: Object.values(OrderStatus).filter(value => typeof value === 'number'), // Only use numeric values + default: OrderStatus.PENDING_PAYMENT + }, +}); + +export const OrderModel = mongoose.model("Order", OrderSchema); diff --git a/apps/merch/src/models/OrderItem.ts b/apps/merch/src/models/OrderItem.ts new file mode 100644 index 00000000..0d061e3e --- /dev/null +++ b/apps/merch/src/models/OrderItem.ts @@ -0,0 +1,16 @@ +import mongoose, { Schema, Document } from "mongoose"; +import { MongoOrderItem } from "../db"; + +export type OrderItemDocument = MongoOrderItem & Document; + +export const OrderItemSchema: Schema = new Schema({ + id: { type: String, required: true }, + name: { type: String, required: true }, + image: { type: String, required: false }, + color: { type: String, required: true }, + size: { type: String, required: true }, + price: { type: Number, required: true }, + quantity: { type: Number, required: true }, +}); + +export const OrderItemModel = mongoose.model("OrderItem", OrderItemSchema); \ No newline at end of file diff --git a/apps/merch/src/routes/checkout.ts b/apps/merch/src/routes/checkout.ts index f6d7b901..3a3427c6 100644 --- a/apps/merch/src/routes/checkout.ts +++ b/apps/merch/src/routes/checkout.ts @@ -51,7 +51,7 @@ export const checkout = (req: Request, res: Response) => { }); } - const orderID = uuidv4(); + const orderId = uuidv4(); const orderTime = new Date(); const expiryTimeMillis = orderTime.getTime() + ORDER_EXPIRY_TIME; const expiryTime = new Date(expiryTimeMillis); @@ -74,14 +74,14 @@ export const checkout = (req: Request, res: Response) => { description: `SCSE Merch Purchase:\n${describeCart( products, cart, - orderID + orderId )}`, }), ]) ) .then(([cart, stripeIntent]) => { console.log("creating order"); - const transactionID = stripeIntent.id; + const transactionId = stripeIntent.id; const orderItems = cart.items.map( (item): OrderItem => ({ id: item.id, @@ -99,12 +99,12 @@ export const checkout = (req: Request, res: Response) => { // }) // ); const order: Order = { - id: orderID, + id: orderId, items: orderItems, - transaction_id: transactionID, - transaction_time: orderTime.toISOString(), - payment_method: "stripe", - customer_email: email, + transactionId: transactionId, + transactionTime: orderTime.toISOString(), + paymentMethod: "stripe", + customerEmail: email, status: OrderStatus.PENDING_PAYMENT, }; // const orderHold: OrderHold = { @@ -128,6 +128,9 @@ export const checkout = (req: Request, res: Response) => { }) .then(([order, stripeIntent]) => { console.log("order created"); + if (!order) { + return; // something went wrong + } res.json({ ...order, expiry: expiryTime.toISOString(), diff --git a/apps/merch/src/routes/orders.ts b/apps/merch/src/routes/orders.ts index 2f4f8b6a..6b92d4a1 100644 --- a/apps/merch/src/routes/orders.ts +++ b/apps/merch/src/routes/orders.ts @@ -17,11 +17,11 @@ export const orderGet = (req: Request<"id">, res: Response) => { }; const censorDetails = (order: Order): Order => { - const customerEmail = order.customer_email.split("@"); + const customerEmail = order.customerEmail.split("@"); return { ...order, - customer_email: starCensor(customerEmail[0]) + "@" + customerEmail.slice(1).join("@"), - transaction_id: starCensor(order.transaction_id), + customerEmail: starCensor(customerEmail[0]) + "@" + customerEmail.slice(1).join("@"), + transactionId: starCensor(order.transactionId), }; }; diff --git a/apps/web/features/merch/services/api.ts b/apps/web/features/merch/services/api.ts index 167b9ae5..c4ebc833 100644 --- a/apps/web/features/merch/services/api.ts +++ b/apps/web/features/merch/services/api.ts @@ -67,11 +67,11 @@ export class Api { return res; } - async getOrder(orderID: string): Promise { - if (!orderID) { + async getOrder(orderId: string): Promise { + if (!orderId) { throw new Error("No order ID"); } - const res = await this.get(`/orders/${orderID}`); + const res = await this.get(`/orders/${orderId}`); return res; } diff --git a/packages/merch-helpers/src/lib/price.ts b/packages/merch-helpers/src/lib/price.ts index 86651a52..8c0d2335 100644 --- a/packages/merch-helpers/src/lib/price.ts +++ b/packages/merch-helpers/src/lib/price.ts @@ -10,8 +10,8 @@ export class PricingError { } } -export const describeCart = (products: Product[], cart: PricedCart, orderID: string): string => { - const entries = [`${frontendURL}/orders/${orderID} | `]; +export const describeCart = (products: Product[], cart: PricedCart, orderId: string): string => { + const entries = [`${frontendURL}/orders/${orderId} | `]; const productMap: Record = {}; for (const product of products) { diff --git a/packages/types/src/lib/merch.ts b/packages/types/src/lib/merch.ts index ac03f82d..f128ec6d 100644 --- a/packages/types/src/lib/merch.ts +++ b/packages/types/src/lib/merch.ts @@ -28,10 +28,10 @@ export enum OrderStatus { export interface Order { id: string; items: OrderItem[]; - transaction_id: string; - transaction_time: string | null; - payment_method: string; - customer_email: string; + transactionId: string; + transactionTime: string | null; + paymentMethod: string; + customerEmail: string; status: OrderStatus; } diff --git a/yarn.lock b/yarn.lock index d8771d95..9b316526 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4329,6 +4329,13 @@ dependencies: sparse-bitfield "^3.0.3" +"@mongodb-js/saslprep@^1.1.5": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz#e974bab8eca9faa88677d4ea4da8d09a52069004" + integrity sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw== + dependencies: + sparse-bitfield "^3.0.3" + "@motionone/animation@^10.12.0", "@motionone/animation@^10.17.0": version "10.17.0" resolved "https://registry.yarnpkg.com/@motionone/animation/-/animation-10.17.0.tgz#7633c6f684b5fee2b61c405881b8c24662c68fca" @@ -7027,6 +7034,13 @@ resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz#1306dbfa53768bcbcfc95a1c8cde367975581859" integrity sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA== +"@types/whatwg-url@^11.0.2": + version "11.0.5" + resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-11.0.5.tgz#aaa2546e60f0c99209ca13360c32c78caf2c409f" + integrity sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ== + dependencies: + "@types/webidl-conversions" "*" + "@types/whatwg-url@^8.2.1": version "8.2.2" resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz#749d5b3873e845897ada99be4448041d4cc39e63" @@ -8335,6 +8349,11 @@ bson@^4.7.2: dependencies: buffer "^5.6.0" +bson@^6.7.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/bson/-/bson-6.8.0.tgz#5063c41ba2437c2b8ff851b50d9e36cb7aaa7525" + integrity sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ== + buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -13339,6 +13358,11 @@ kareem@2.5.1: resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.5.1.tgz#7b8203e11819a8e77a34b3517d3ead206764d15d" integrity sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA== +kareem@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.6.3.tgz#23168ec8ffb6c1abfd31b7169a6fb1dd285992ac" + integrity sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q== + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -14369,6 +14393,14 @@ mongodb-connection-string-url@^2.6.0: "@types/whatwg-url" "^8.2.1" whatwg-url "^11.0.0" +mongodb-connection-string-url@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz#c13e6ac284ae401752ebafdb8cd7f16c6723b141" + integrity sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg== + dependencies: + "@types/whatwg-url" "^11.0.2" + whatwg-url "^13.0.0" + mongodb@4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.17.1.tgz#ccff6ddbda106d5e06c25b0e4df454fd36c5f819" @@ -14381,6 +14413,15 @@ mongodb@4.17.1: "@aws-sdk/credential-providers" "^3.186.0" "@mongodb-js/saslprep" "^1.1.0" +mongodb@6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-6.8.0.tgz#680450f113cdea6d2d9f7121fe57cd29111fd2ce" + integrity sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw== + dependencies: + "@mongodb-js/saslprep" "^1.1.5" + bson "^6.7.0" + mongodb-connection-string-url "^3.0.0" + mongoose-aggregate-paginate-v2@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/mongoose-aggregate-paginate-v2/-/mongoose-aggregate-paginate-v2-1.0.6.tgz#fd2f2564d1bbf52f49a196f0b7b03675913dacca" @@ -14404,6 +14445,19 @@ mongoose@6.12.3: ms "2.1.3" sift "16.0.1" +mongoose@^8.6.1: + version "8.6.1" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-8.6.1.tgz#b353b5c6f901ffb01f53a746c1dc4aacd39a87f9" + integrity sha512-dppGcYqvsdg+VcnqXR5b467V4a+iNhmvkfYNpEPi6AjaUxnz6ioEDmrMLOi+sOWjvoHapuwPOigV4f2l7HC6ag== + dependencies: + bson "^6.7.0" + kareem "2.6.3" + mongodb "6.8.0" + mpath "0.9.0" + mquery "5.0.0" + ms "2.1.3" + sift "17.1.3" + morgan@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" @@ -14427,6 +14481,13 @@ mquery@4.0.3: dependencies: debug "4.x" +mquery@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-5.0.0.tgz#a95be5dfc610b23862df34a47d3e5d60e110695d" + integrity sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg== + dependencies: + debug "4.x" + mrmime@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" @@ -16068,7 +16129,7 @@ punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== -punycode@^2.1.0, punycode@^2.1.1: +punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== @@ -17200,6 +17261,11 @@ sift@16.0.1: resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.1.tgz#e9c2ccc72191585008cf3e36fc447b2d2633a053" integrity sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ== +sift@17.1.3: + version "17.1.3" + resolved "https://registry.yarnpkg.com/sift/-/sift-17.1.3.tgz#9d2000d4d41586880b0079b5183d839c7a142bf7" + integrity sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ== + signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" @@ -18196,6 +18262,13 @@ tr46@^3.0.0: dependencies: punycode "^2.1.1" +tr46@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-4.1.1.tgz#281a758dcc82aeb4fe38c7dfe4d11a395aac8469" + integrity sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw== + dependencies: + punycode "^2.3.0" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -19114,6 +19187,14 @@ whatwg-url@^11.0.0: tr46 "^3.0.0" webidl-conversions "^7.0.0" +whatwg-url@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-13.0.0.tgz#b7b536aca48306394a34e44bda8e99f332410f8f" + integrity sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig== + dependencies: + tr46 "^4.1.1" + webidl-conversions "^7.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" From 4c889f023265aad9e229d54f550f846540912fe6 Mon Sep 17 00:00:00 2001 From: limivann <71662324+limivann@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:32:23 +0800 Subject: [PATCH 2/4] Add env example --- apps/merch/.env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/merch/.env.example b/apps/merch/.env.example index b90efd39..25666e5e 100644 --- a/apps/merch/.env.example +++ b/apps/merch/.env.example @@ -4,3 +4,4 @@ ORDER_TABLE_NAME= ORDER_HOLD_TABLE_NAME= CORS_ORIGIN=http://localhost:3001 STRIPE_SECRET_KEY= +MONGODB_URI= \ No newline at end of file From c5ed9548dd16d7026c174103982d1779a860d4b5 Mon Sep 17 00:00:00 2001 From: limivann <71662324+limivann@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:14:55 +0800 Subject: [PATCH 3/4] sync fe changes --- apps/web/pages/merch/orders/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/pages/merch/orders/index.tsx b/apps/web/pages/merch/orders/index.tsx index 397c1836..1c372f76 100644 --- a/apps/web/pages/merch/orders/index.tsx +++ b/apps/web/pages/merch/orders/index.tsx @@ -101,8 +101,8 @@ const OrderSummary: React.FC = () => { Order date:{" "} - {orderState?.transaction_time - ? new Date(`${orderState.transaction_time}`).toLocaleString( + {orderState?.transactionTime + ? new Date(`${orderState.transactionTime}`).toLocaleString( "en-sg" ) : ""} @@ -141,8 +141,8 @@ const OrderSummary: React.FC = () => { Order date:{" "} - {orderState?.transaction_time - ? new Date(`${orderState.transaction_time}`).toLocaleString( + {orderState?.transactionTime + ? new Date(`${orderState.transactionTime}`).toLocaleString( "en-sg" ) : ""} From 13994475c98038ed71022c699cc6da26c677db96 Mon Sep 17 00:00:00 2001 From: limivann <71662324+limivann@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:59:09 +0800 Subject: [PATCH 4/4] Refactor --- apps/merch/src/db/mongodb.ts | 7 ------- apps/merch/src/models/Order.ts | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/merch/src/db/mongodb.ts b/apps/merch/src/db/mongodb.ts index 1bbdef8a..0e9e3693 100644 --- a/apps/merch/src/db/mongodb.ts +++ b/apps/merch/src/db/mongodb.ts @@ -8,13 +8,6 @@ export class NotFoundError { } } -export class ItemExistError { - message: string; - constructor(id = "") { - this.message = "Item with " + id + " already exists."; - } -} - // readTable scans the table for all entries export const readTable = async(model: Model): Promise => { const response = await model.find().exec(); diff --git a/apps/merch/src/models/Order.ts b/apps/merch/src/models/Order.ts index 1f2bbec8..d7c53d91 100644 --- a/apps/merch/src/models/Order.ts +++ b/apps/merch/src/models/Order.ts @@ -6,7 +6,7 @@ import { MongoOrder } from "../db"; export type OrderDocument = MongoOrder & Document; const OrderSchema: Schema = new Schema({ - _id: { type: String }, + _id: { type: String, required: true }, items: [ OrderItemSchema ], transactionId: { type: String, default: "" }, transactionTime: { type: String, default: null },