Rocky_Mountain_Vending/lib/convex-service.ts

160 lines
3.8 KiB
TypeScript

import { fetchQuery } from "convex/nextjs"
import { api } from "@/convex/_generated/api"
import { hasConvexUrl } from "@/lib/convex-config"
import type { Product } from "@/lib/products/types"
import type { Manual } from "@/lib/manuals-types"
type ConvexProductDoc = {
_id: string
name: string
description?: string
price: number
currency: string
images: string[]
metadata?: Record<string, string>
stripeProductId?: string
stripePriceId?: string
active: boolean
}
type ConvexManualDoc = {
filename: string
path: string
manufacturer: string
category: string
size?: number
lastModified?: number
searchTerms?: string[]
commonNames?: string[]
thumbnailUrl?: string
manualUrl?: string
}
type ConvexOrderItem = {
productId?: string | null
productName: string
price: number
quantity: number
priceId: string
image?: string
}
export type ConvexAdminOrder = {
id: string
customerEmail: string
customerName?: string
totalAmount: number
currency: string
status: "pending" | "paid" | "fulfilled" | "cancelled" | "refunded"
stripeSessionId: string | null
paymentIntentId: string | null
createdAt: string
updatedAt: string
shippingAddress?: {
name?: string
address?: string
city?: string
state?: string
zipCode?: string
country?: string
}
items: ConvexOrderItem[]
}
function mapConvexProduct(product: ConvexProductDoc): Product {
return {
id: product._id,
stripeId: product.stripeProductId ?? product._id,
name: product.name,
description: product.description ?? null,
price: product.price,
currency: product.currency,
images: product.images ?? [],
metadata: product.metadata,
priceId: product.stripePriceId,
}
}
function mapConvexManual(manual: ConvexManualDoc): Manual {
return {
filename: manual.filename,
path: manual.manualUrl || manual.path,
manufacturer: manual.manufacturer,
category: manual.category,
size: manual.size,
lastModified: manual.lastModified ? new Date(manual.lastModified) : undefined,
searchTerms: manual.searchTerms,
commonNames: manual.commonNames,
thumbnailUrl: manual.thumbnailUrl,
}
}
export async function listConvexProducts(): Promise<Product[]> {
if (!hasConvexUrl()) {
return []
}
const products = await fetchQuery(api.products.listActive, {})
return (products as ConvexProductDoc[]).map(mapConvexProduct)
}
export async function listConvexAdminProducts(search?: string): Promise<Product[]> {
if (!hasConvexUrl()) {
return []
}
const products = await fetchQuery(api.products.listAdmin, { search })
return (products as ConvexProductDoc[]).map(mapConvexProduct)
}
export async function getConvexProduct(id: string): Promise<Product | null> {
if (!hasConvexUrl()) {
return null
}
const products = await fetchQuery(api.products.listAdmin, {})
const match = (products as ConvexProductDoc[]).find((product) => {
return product._id === id || product.stripeProductId === id
})
return match ? mapConvexProduct(match) : null
}
export async function listConvexManuals(): Promise<Manual[]> {
if (!hasConvexUrl()) {
return []
}
const manuals = await fetchQuery(api.manuals.list, {})
return (manuals as ConvexManualDoc[]).map(mapConvexManual)
}
export async function getConvexManualDashboard() {
if (!hasConvexUrl()) {
return null
}
return await fetchQuery(api.manuals.dashboard, {})
}
export async function getConvexOrderMetrics() {
if (!hasConvexUrl()) {
return null
}
return await fetchQuery(api.orders.getMetrics, {})
}
export async function listConvexOrders(options?: {
status?: ConvexAdminOrder["status"]
search?: string
}): Promise<ConvexAdminOrder[]> {
if (!hasConvexUrl()) {
return []
}
return await fetchQuery(api.orders.listAdmin, {
status: options?.status,
search: options?.search,
})
}