feat(backend): move product pricing to async persisted jobs
This commit is contained in:
parent
c869f88db2
commit
0e439b4ca7
18 changed files with 468 additions and 67 deletions
|
|
@ -9,6 +9,7 @@ import type {
|
|||
MedicationUsage,
|
||||
PartOfDay,
|
||||
Product,
|
||||
ProductSummary,
|
||||
ProductContext,
|
||||
ProductEffectProfile,
|
||||
ProductInventory,
|
||||
|
|
@ -70,6 +71,20 @@ export function getProducts(
|
|||
return api.get(`/products${qs ? `?${qs}` : ""}`);
|
||||
}
|
||||
|
||||
export function getProductSummaries(
|
||||
params: ProductListParams = {},
|
||||
): Promise<ProductSummary[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.category) q.set("category", params.category);
|
||||
if (params.brand) q.set("brand", params.brand);
|
||||
if (params.targets) params.targets.forEach((t) => q.append("targets", t));
|
||||
if (params.is_medication != null)
|
||||
q.set("is_medication", String(params.is_medication));
|
||||
if (params.is_tool != null) q.set("is_tool", String(params.is_tool));
|
||||
const qs = q.toString();
|
||||
return api.get(`/products/summary${qs ? `?${qs}` : ""}`);
|
||||
}
|
||||
|
||||
export const getProduct = (id: string): Promise<Product> =>
|
||||
api.get(`/products/${id}`);
|
||||
export const createProduct = (
|
||||
|
|
|
|||
|
|
@ -183,6 +183,19 @@ export interface Product {
|
|||
inventory: ProductInventory[];
|
||||
}
|
||||
|
||||
export interface ProductSummary {
|
||||
id: string;
|
||||
name: string;
|
||||
brand: string;
|
||||
category: ProductCategory;
|
||||
recommended_time: DayTime;
|
||||
targets: SkinConcern[];
|
||||
is_owned: boolean;
|
||||
price_tier?: PriceTier;
|
||||
price_per_use_pln?: number;
|
||||
price_tier_source?: PriceTierSource;
|
||||
}
|
||||
|
||||
// ─── Routine types ───────────────────────────────────────────────────────────
|
||||
|
||||
export interface RoutineStep {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { getProducts } from '$lib/api';
|
||||
import { getProductSummaries } from '$lib/api';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
const products = await getProducts();
|
||||
const products = await getProductSummaries();
|
||||
return { products };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import type { Product } from '$lib/types';
|
||||
import type { ProductSummary } from '$lib/types';
|
||||
import { resolve } from '$app/paths';
|
||||
import { SvelteMap } from 'svelte/reactivity';
|
||||
import { m } from '$lib/paraglide/messages.js';
|
||||
|
|
@ -31,8 +31,8 @@
|
|||
'spf', 'mask', 'exfoliant', 'hair_treatment', 'tool', 'spot_treatment', 'oil'
|
||||
];
|
||||
|
||||
function isOwned(p: Product): boolean {
|
||||
return p.inventory?.some(inv => !inv.finished_at) ?? false;
|
||||
function isOwned(p: ProductSummary): boolean {
|
||||
return p.is_owned;
|
||||
}
|
||||
|
||||
function setSort(nextKey: SortKey): void {
|
||||
|
|
@ -90,7 +90,7 @@
|
|||
return sortDirection === 'asc' ? cmp : -cmp;
|
||||
});
|
||||
|
||||
const map = new SvelteMap<string, Product[]>();
|
||||
const map = new SvelteMap<string, ProductSummary[]>();
|
||||
for (const p of items) {
|
||||
if (!map.has(p.category)) map.set(p.category, []);
|
||||
map.get(p.category)!.push(p);
|
||||
|
|
@ -121,8 +121,8 @@
|
|||
return value;
|
||||
}
|
||||
|
||||
function getPricePerUse(product: Product): number | undefined {
|
||||
return (product as Product & { price_per_use_pln?: number }).price_per_use_pln;
|
||||
function getPricePerUse(product: ProductSummary): number | undefined {
|
||||
return product.price_per_use_pln;
|
||||
}
|
||||
|
||||
function formatCategory(value: string): string {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { addRoutineStep, deleteRoutine, deleteRoutineStep, getProducts, getRoutine } from '$lib/api';
|
||||
import { addRoutineStep, deleteRoutine, deleteRoutineStep, getProductSummaries, getRoutine } from '$lib/api';
|
||||
import { error, fail, redirect } from '@sveltejs/kit';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
try {
|
||||
const [routine, products] = await Promise.all([getRoutine(params.id), getProducts()]);
|
||||
const [routine, products] = await Promise.all([getRoutine(params.id), getProductSummaries()]);
|
||||
return { routine, products };
|
||||
} catch {
|
||||
error(404, 'Routine not found');
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { addRoutineStep, createRoutine, getProducts, suggestBatch, suggestRoutine } from '$lib/api';
|
||||
import { addRoutineStep, createRoutine, getProductSummaries, suggestBatch, suggestRoutine } from '$lib/api';
|
||||
import { fail, redirect } from '@sveltejs/kit';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
const products = await getProducts();
|
||||
const products = await getProductSummaries();
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
return { products, today };
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue