add product image and variant value
This commit is contained in:
@@ -39,3 +39,20 @@
|
|||||||
- Review all names before running the populate script
|
- Review all names before running the populate script
|
||||||
|
|
||||||
The final CSV will have all original columns plus the new "icon_name" column with your custom names.
|
The final CSV will have all original columns plus the new "icon_name" column with your custom names.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Import named icons into the database
|
||||||
|
|
||||||
|
To insert icons from `named_icons.csv` into the `icons` table:
|
||||||
|
|
||||||
|
1. **Ensure your database is running** and `.env` in the project root has `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, and `DB_PASS` (same as for `dump-icons.sh` / `restore-icons.sh`).
|
||||||
|
|
||||||
|
2. **Optional:** Set which icon group to attach icons to:
|
||||||
|
- `ICON_GROUP_ID` (default: `01KD7DG4VCTWZRSA54M3PEJ6NW` — پک آیکون 1). Use an existing `icon_groups.id` from your DB.
|
||||||
|
|
||||||
|
3. **From the project root**, run:
|
||||||
|
```bash
|
||||||
|
node dump/import-named-icons.js
|
||||||
|
```
|
||||||
|
The script reads `dump/named_icons.csv` (columns: Index, Name, URL) and inserts one row per URL into `icons` with generated ULID and timestamps. The **Name** column is not stored (the `icons` table has no name column); only **URL** and **group_id** are used.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,103 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Import icons from dump/named_icons.csv into the icons table.
|
||||||
|
* Uses DB_* env vars (from .env or environment). Icons are assigned to ICON_GROUP_ID.
|
||||||
|
*
|
||||||
|
* Run from project root: node dump/import-named-icons.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { Client } = require('pg');
|
||||||
|
const { ulid } = require('ulid');
|
||||||
|
|
||||||
|
// Load .env from project root
|
||||||
|
const envPath = path.join(__dirname, '..', '.env');
|
||||||
|
if (fs.existsSync(envPath)) {
|
||||||
|
const content = fs.readFileSync(envPath, 'utf8');
|
||||||
|
content.split('\n').forEach((line) => {
|
||||||
|
const trimmed = line.replace(/^\s+|\s+$/, '').replace(/#.*$/, '').trim();
|
||||||
|
if (!trimmed || !/^[A-Za-z_][A-Za-z0-9_]*=/.test(trimmed)) return;
|
||||||
|
const eq = trimmed.indexOf('=');
|
||||||
|
const key = trimmed.slice(0, eq);
|
||||||
|
const value = trimmed.slice(eq + 1).replace(/^["']|["']$/g, '');
|
||||||
|
if (!process.env[key]) process.env[key] = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const DB_HOST = process.env.DB_HOST || 'localhost';
|
||||||
|
const DB_PORT = process.env.DB_PORT || '5432';
|
||||||
|
const DB_NAME = process.env.DB_NAME || 'dmenu';
|
||||||
|
const DB_USER = process.env.DB_USER || 'postgres';
|
||||||
|
const DB_PASS = process.env.DB_PASS || '';
|
||||||
|
const ICON_GROUP_ID = process.env.ICON_GROUP_ID || '01KD7DG4VCTWZRSA54M3PEJ6NW';
|
||||||
|
|
||||||
|
const csvPath = path.join(__dirname, 'named_icons.csv');
|
||||||
|
|
||||||
|
function parseCsvLine(line) {
|
||||||
|
const parts = line.split(',');
|
||||||
|
if (parts.length < 3) return null;
|
||||||
|
const index = parts[0].trim();
|
||||||
|
const url = parts[parts.length - 1].trim();
|
||||||
|
const name = parts.slice(1, -1).join(',').trim();
|
||||||
|
return { index, name, url };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
if (!fs.existsSync(csvPath)) {
|
||||||
|
console.error('Error: named_icons.csv not found at', csvPath);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const csvContent = fs.readFileSync(csvPath, 'utf8');
|
||||||
|
const lines = csvContent.split('\n').filter((l) => l.trim());
|
||||||
|
const header = lines[0];
|
||||||
|
const dataLines = lines.slice(1);
|
||||||
|
|
||||||
|
const rows = [];
|
||||||
|
for (const line of dataLines) {
|
||||||
|
const row = parseCsvLine(line);
|
||||||
|
if (row && row.url) rows.push(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rows.length === 0) {
|
||||||
|
console.error('Error: No valid rows found in named_icons.csv');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = new Client({
|
||||||
|
host: DB_HOST,
|
||||||
|
port: parseInt(DB_PORT, 10),
|
||||||
|
database: DB_NAME,
|
||||||
|
user: DB_USER,
|
||||||
|
password: DB_PASS,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Database connection failed:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = new Date().toISOString();
|
||||||
|
let inserted = 0;
|
||||||
|
|
||||||
|
for (const row of rows) {
|
||||||
|
const id = ulid();
|
||||||
|
await client.query(
|
||||||
|
`INSERT INTO icons (id, created_at, updated_at, deleted_at, url, group_id)
|
||||||
|
VALUES ($1, $2::timestamptz, $3::timestamptz, NULL, $4, $5)`,
|
||||||
|
[id, now, now, row.url, ICON_GROUP_ID]
|
||||||
|
);
|
||||||
|
inserted++;
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.end();
|
||||||
|
console.log(`Done. Inserted ${inserted} icons.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -3,6 +3,8 @@ import type { OrderCouponDetail, OrderUserAddress } from 'src/modules/orders/int
|
|||||||
export interface CartItem {
|
export interface CartItem {
|
||||||
variantId: string;
|
variantId: string;
|
||||||
productTitle?: string;
|
productTitle?: string;
|
||||||
|
variantValue?: string;
|
||||||
|
image?: string;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
price: number;
|
price: number;
|
||||||
discount: number;
|
discount: number;
|
||||||
|
|||||||
@@ -21,10 +21,13 @@ export class CartItemService {
|
|||||||
createCartItem(variant: Variant, quantity: number): CartItem {
|
createCartItem(variant: Variant, quantity: number): CartItem {
|
||||||
const itemPrice = variant.price || 0;
|
const itemPrice = variant.price || 0;
|
||||||
const itemDiscount = variant.product.discount || 0;
|
const itemDiscount = variant.product.discount || 0;
|
||||||
|
const image = variant.product.images?.[0];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
variantId: variant.id,
|
variantId: variant.id,
|
||||||
productTitle: variant.product.title,
|
productTitle: variant.product.title,
|
||||||
|
variantValue: variant.value,
|
||||||
|
image,
|
||||||
quantity,
|
quantity,
|
||||||
price: itemPrice,
|
price: itemPrice,
|
||||||
discount: itemDiscount,
|
discount: itemDiscount,
|
||||||
@@ -38,10 +41,13 @@ export class CartItemService {
|
|||||||
buildCartItemFromFood(variant: Variant, quantity: number, previous?: CartItem): CartItem {
|
buildCartItemFromFood(variant: Variant, quantity: number, previous?: CartItem): CartItem {
|
||||||
const itemPrice = variant.price || 0;
|
const itemPrice = variant.price || 0;
|
||||||
const itemDiscount = variant.product.discount || 0;
|
const itemDiscount = variant.product.discount || 0;
|
||||||
|
const image = variant.product.images?.[0];
|
||||||
return {
|
return {
|
||||||
...(previous ?? ({} as CartItem)),
|
...(previous ?? ({} as CartItem)),
|
||||||
variantId: variant.id,
|
variantId: variant.id,
|
||||||
productTitle: variant.product.title,
|
productTitle: variant.product.title,
|
||||||
|
variantValue: variant.value,
|
||||||
|
image,
|
||||||
quantity,
|
quantity,
|
||||||
price: itemPrice,
|
price: itemPrice,
|
||||||
discount: itemDiscount,
|
discount: itemDiscount,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export class FoodController {
|
|||||||
@Get('public/products/shop/:slug')
|
@Get('public/products/shop/:slug')
|
||||||
@ApiOperation({ summary: 'Get all products by shop slug' })
|
@ApiOperation({ summary: 'Get all products by shop slug' })
|
||||||
@ApiHeader(API_HEADER_SLUG)
|
@ApiHeader(API_HEADER_SLUG)
|
||||||
|
@ApiQuery({ name: 'categoryId', required: false, type: String })
|
||||||
findAllByRestaurant(@Param('slug') slug: string, @Query('categoryId') categoryId?: string) {
|
findAllByRestaurant(@Param('slug') slug: string, @Query('categoryId') categoryId?: string) {
|
||||||
return this.productService.findByShop(slug, categoryId);
|
return this.productService.findByShop(slug, categoryId);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user