u
This commit is contained in:
3
src/demo/mode.js
Normal file
3
src/demo/mode.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export function isDemoMode() {
|
||||
return String(process.env.DEMO_MODE || '').toLowerCase() === 'true';
|
||||
}
|
||||
139
src/demo/store.js
Normal file
139
src/demo/store.js
Normal file
@@ -0,0 +1,139 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { setActiveShop, setActiveShopSubshop } from '../shop.js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const DEMO_ROOT = path.join(__dirname, '..', '..', 'demo');
|
||||
const CATALOG_PATH = path.join(DEMO_ROOT, 'catalog.json');
|
||||
const IMAGES_DIR = path.join(DEMO_ROOT, 'images');
|
||||
|
||||
let catalog = null;
|
||||
let nextDemoOrderId = 1;
|
||||
|
||||
function ensureLoaded() {
|
||||
if (!catalog) {
|
||||
throw new Error('Demo catalog is not loaded. Call loadDemoCatalog() at startup.');
|
||||
}
|
||||
return catalog;
|
||||
}
|
||||
|
||||
function afterCursor(rows, cursor, lastChangedKey = 'lastChanged') {
|
||||
const c = Number(cursor) || 0;
|
||||
return rows
|
||||
.filter((row) => Number(row[lastChangedKey]) > c)
|
||||
.sort((a, b) => Number(a[lastChangedKey]) - Number(b[lastChangedKey]));
|
||||
}
|
||||
|
||||
export async function loadDemoCatalog() {
|
||||
if (!fs.existsSync(CATALOG_PATH)) {
|
||||
throw new Error(
|
||||
`Demo catalog missing at ${CATALOG_PATH}. Run: npm run demo:generate`
|
||||
);
|
||||
}
|
||||
|
||||
const raw = fs.readFileSync(CATALOG_PATH, 'utf8');
|
||||
catalog = JSON.parse(raw);
|
||||
|
||||
if (!Array.isArray(catalog.products) || catalog.products.length === 0) {
|
||||
throw new Error('Demo catalog has no products.');
|
||||
}
|
||||
|
||||
setActiveShop(1);
|
||||
setActiveShopSubshop(1);
|
||||
nextDemoOrderId = Number(catalog.maxOrderId || 0) + 1;
|
||||
|
||||
return {
|
||||
categories: catalog.categories.length,
|
||||
products: catalog.products.length,
|
||||
customerGroups: catalog.customerGroups.length,
|
||||
composites: catalog.composites.length,
|
||||
imagesDir: IMAGES_DIR,
|
||||
};
|
||||
}
|
||||
|
||||
export function getDemoProductList({ cursor = 0, limit = 20 } = {}) {
|
||||
return afterCursor(ensureLoaded().products, cursor).slice(0, limit);
|
||||
}
|
||||
|
||||
export function getDemoProductCount({ cursor = 0 } = {}) {
|
||||
return afterCursor(ensureLoaded().products, cursor).length;
|
||||
}
|
||||
|
||||
export function getDemoCategoryList({ cursor = 0, limit = 20 } = {}) {
|
||||
const data = ensureLoaded();
|
||||
return afterCursor(data.categories, cursor).slice(0, limit).map((category) => ({
|
||||
_id: category._id,
|
||||
imghash: category.imghash,
|
||||
imgsrc: category.imgsrc,
|
||||
name: category.name,
|
||||
pid: category.pid,
|
||||
discounts: category.discounts ?? [],
|
||||
sort: category.sort,
|
||||
lastChanged: category.lastChanged,
|
||||
}));
|
||||
}
|
||||
|
||||
export function getDemoCategoryCount({ cursor = 0 } = {}) {
|
||||
return afterCursor(ensureLoaded().categories, cursor).length;
|
||||
}
|
||||
|
||||
export function getDemoCustomerGroupIds() {
|
||||
return ensureLoaded().customerGroups.map((g) => Number(g.customerGroupId));
|
||||
}
|
||||
|
||||
export function getDemoCustomerGroupList({ cursor = 0 } = {}) {
|
||||
return afterCursor(ensureLoaded().customerGroups, cursor);
|
||||
}
|
||||
|
||||
export function getDemoCustomerGroupCount({ cursor = 0 } = {}) {
|
||||
return afterCursor(ensureLoaded().customerGroups, cursor).length;
|
||||
}
|
||||
|
||||
export function getDemoCompositeProductList({ cursor = 0, limit = 100 } = {}) {
|
||||
return afterCursor(ensureLoaded().composites, cursor).slice(0, limit);
|
||||
}
|
||||
|
||||
export function getDemoCompositeProductCount({ cursor = 0 } = {}) {
|
||||
// Match MSSQL semantics: count distinct composite parent products after cursor
|
||||
const rows = afterCursor(ensureLoaded().composites, cursor);
|
||||
return new Set(rows.map((r) => r.productId)).size;
|
||||
}
|
||||
|
||||
export function getDemoDeletedEntityList({ cursor = 0, limit = 600 } = {}) {
|
||||
return afterCursor(ensureLoaded().deletedEntities, cursor).slice(0, limit);
|
||||
}
|
||||
|
||||
export function getDemoDeletedEntityCount({ cursor = 0 } = {}) {
|
||||
return afterCursor(ensureLoaded().deletedEntities, cursor).length;
|
||||
}
|
||||
|
||||
export function getDemoMaxOrderIdCount() {
|
||||
return Number(ensureLoaded().maxOrderId || 0);
|
||||
}
|
||||
|
||||
export async function getDemoImageByHash(hash) {
|
||||
ensureLoaded();
|
||||
if (!hash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const filePath = path.join(IMAGES_DIR, `${hash}.jpg`);
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const buffer = fs.readFileSync(filePath);
|
||||
return { buffer, contentType: 'image/jpeg' };
|
||||
}
|
||||
|
||||
export async function createDemoOrder(order) {
|
||||
ensureLoaded();
|
||||
const orderId = nextDemoOrderId++;
|
||||
const externalId = String(order?.externalId ?? orderId);
|
||||
return {
|
||||
orderId: String(orderId),
|
||||
orderNumber: `DEMO-${externalId}`,
|
||||
alreadyExists: false,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user