category icons

This commit is contained in:
2025-12-28 14:49:06 +03:30
parent 1265fa72bc
commit 6114dd3edc
7 changed files with 4144 additions and 3096 deletions
+361
View File
@@ -2,8 +2,367 @@ import type { EntityManager } from '@mikro-orm/core';
import { Category } from '../modules/foods/entities/category.entity';
import type { Restaurant } from '../modules/restaurants/entities/restaurant.entity';
import { categoriesData } from './data/categories.data';
import * as fs from 'fs';
import * as path from 'path';
interface IconData {
index: number;
name: string;
url: string;
}
export class CategoriesSeeder {
private icons: IconData[] = [];
private iconIndex = 0;
private loadIcons(): void {
if (this.icons.length > 0) return;
const iconsPath = path.join(process.cwd(), 'dump', 'named_icons.csv');
const csvContent = fs.readFileSync(iconsPath, 'utf-8');
const lines = csvContent.split('\n').slice(1); // Skip header
this.icons = lines
.filter(line => line.trim())
.map(line => {
const parts = line.split(',');
return {
index: parseInt(parts[0].replace(/"/g, '')),
name: parts[1].replace(/"/g, ''),
url: parts[2].replace(/"/g, '')
};
});
}
private getIconForCategory(categoryTitle: string): string | undefined {
this.loadIcons();
if (this.icons.length === 0) return undefined;
// Create a mapping of keywords to icon names
const iconMapping: Record<string, string[]> = {
// Pizza
'پیتزا': ['pizza'],
// Pasta
'پاستا': ['fast-food'],
// Steak
'استیک': ['meat', 'meat 2'],
// Burger
'برگر': ['hanburger'],
// Salad
'سالاد': ['broccoli'],
// Appetizer/Appetizers
'پیش غذا': ['chicken', 'fast-food'],
// Main Course
'غذای اصلی': ['hanburger', 'meat'],
'خوراک': ['hanburger', 'meat'],
'ناهار': ['hanburger', 'meat'],
// Sandwich
'ساندویچ': ['bread'],
// Fried foods
'سوخاری': ['chicken', 'fast-food'],
// Cake/Dessert
'کیک': ['cookie1', 'cookie2'],
'دسر': ['cookie1', 'cookie2'],
// Ice Cream
'بستنی': ['ice cream', 'ice cream 3'],
'آیس': ['ice cream'],
// Breakfast
'صبحانه': ['bread', 'egg'],
// Drinks - general
'نوشیدنی': ['drink', 'drink2', 'bottle1', 'bottle2'],
// Coffee
'قهوه': ['drink', 'drink2'],
'اسپرسو': ['drink'],
'کافی': ['drink'],
// Tea
'چای': ['drink', 'drink2'],
'دمنوش': ['drink', 'drink2'],
// Cocktail/Mocktail
'ماکتل': ['wine glass', 'wine glass 2'],
'موهیتو': ['wine glass'],
// Shake/Smoothie
'شیک': ['ice cream'],
'اسموتی': ['ice cream'],
// Juice
'آبمیوه': ['juice', 'juice2', 'juice3'],
'ویتامینه': ['juice', 'juice2', 'juice3'],
// Hot Dog
'هات داگ': ['hot dog'],
// BBQ
'باربیکیو': ['barbecue', 'barbeque2'],
// BBQ Skewers
'کباب': ['skewer'],
// Soup
'آش': ['jar', 'dish'],
// Bread
'نان': ['bread'],
// Donut
'دونات': ['donuts'],
// Fish
'دریایی': ['fish'],
'ماهی': ['fish'],
// Chicken
'مرغ': ['chicken'],
// Egg
'تخم': ['egg', 'fried egg'],
// Vegetable
'سبزی': ['broccoli'],
// Fruit
'میوه': ['strawberry', 'cherry', 'grape', 'watermelon'],
// Milk
'شیر': ['bottle1'], // Note: there's no milk icon, using a generic one
// Cookie
'کوکی': ['cookie1', 'cookie2'],
// French Fries
'سیب زمینی': ['french fries'],
// Fast Food
'فست فود': ['fast-food'],
// Bakery
'نانوایی': ['bread'],
// Ice Tea
'آیس تی': ['drink', 'drink2'],
// Hot Pot
'حلیم': ['jar', 'dish'],
// Taco
'تاکو': ['taco'],
// Nachos
'ناچو': ['fast-food'],
// Sushi
'سوشی': ['fish'],
// Dumpling
'غالوش': ['basket'],
// Tempura
'تمپورا': ['fish'],
// Tofu
'توفو': ['jar'],
// Bibimbap
'بیبیمباب': ['fast-food'],
// Boba
'بوبا': ['drink', 'drink2'],
// Fish and Chips
'فیش اند چیپس': ['fish', 'french fries'],
// Focaccia
'فوکاچیا': ['bread'],
// Martini
'مارتینی': ['wine glass'],
// Mochi
'موچی': ['donuts'],
// Pancake
'پن کیک': ['bread'],
// Quesadilla
'کوئزادیا': ['quesadilla'],
// Origami
'اوريگامي': ['basket'],
// Pudding
'پودینگ': ['jar'],
// Sweet
'شیرین': ['candy'],
// Crossant
'کروسان': ['bread'],
// Bio
'بیو': ['broccoli'],
// Lemon
'لیمو': ['lemon'],
// Candy
'شیرینی': ['candy'],
// Lollipop
'آب نبات': ['lollipop'],
// Cherry
'گیلاس': ['cherry'],
// Strawberry
'توت فرنگی': ['strawberry'],
// Watermelon
'هندوانه': ['watermelon'],
// Avocado
'آووکادو': ['avocado'],
// Banana
'موز': ['banana'],
// Carrot
'هویج': ['carrot'],
// Cheese
'پنیر': ['cheese', 'cheese2'],
// Tomato
'گوجه': ['tomato'], // Note: no tomato icon
// Onion
'پیاز': ['onion'],
// Olive
'زیتون': ['olive'],
// Nuts
'آجیل': ['nuts'],
// Scales (for weighing)
'ترازو': ['scales'],
// Whisk
'همزن': ['whisk', 'whisk'],
// Mortar
'هاون': ['mortar'],
// Rolling pin
'والت': ['rolling pin'],
// Knife
'چاقو': ['knife'],
// Baby food
'کودک': ['baby bottle', 'baby bottle', 'baby pacifier'],
// Hat (chef hat)
'کلاه': ['hat robe', 'hat robe 2'],
// Bread
'نان': ['bread', 'loaf of bread', 'loaf of bread 2'],
// Candle (birthday)
'شمع': ['candle'],
// Fire
'آتش': ['fire'],
// Refrigerator
'یخچال': ['refrigerator'],
// Kitchen stove
'اجاق': ['kitchen stove'],
// Mixer
'میکسر': ['mixer'],
// Jar
'شیشه': ['jar'],
// Jelly
'ژله': ['jelly'],
// Soap
'صابون': ['soap'],
// Dish
'ظرف': ['dish'],
// Basket
'سبد': ['basket'],
// Salt
'نمک': ['solt'],
// Eggplant
'بادمجان': ['egg plant'],
// Wine
'شراب': ['wine glass', 'wine glass 2', 'wine glass 3'],
// Plate
'بشقاب': ['dish'],
// Fork and knife
'چنگال': ['spoon and fork 1', 'spoon and fork 2', 'spoon and knife', 'fork and knife'],
// Toast
'تست': ['toast']
};
// Find matching icon based on category title
for (const [keyword, iconNames] of Object.entries(iconMapping)) {
if (categoryTitle.includes(keyword)) {
// Find the first available icon from the list
for (const iconName of iconNames) {
const icon = this.icons.find(i => i.name.toLowerCase() === iconName.toLowerCase());
if (icon) {
return icon.url;
}
}
}
}
// Fallback: try to find any icon that might be related by partial name match
for (const icon of this.icons) {
const lowerTitle = categoryTitle.toLowerCase();
const lowerIconName = icon.name.toLowerCase();
// Check if any word in the category title matches part of the icon name
const titleWords = lowerTitle.split(/\s+/);
for (const word of titleWords) {
if (word.length > 2 && lowerIconName.includes(word)) {
return icon.url;
}
}
}
// Final fallback: return a random icon
const randomIndex = Math.floor(Math.random() * this.icons.length);
return this.icons[randomIndex]?.url;
}
async run(em: EntityManager, restaurantsMap: Map<string, Restaurant>): Promise<Map<string, Category>> {
const categoriesMap = new Map<string, Category>();
@@ -17,10 +376,12 @@ export class CategoriesSeeder {
});
if (!existing) {
const avatarUrl = this.getIconForCategory(catData.title);
const category = em.create(Category, {
title: catData.title,
restaurant,
isActive: true,
avatarUrl,
});
em.persist(category);
categoriesMap.set(`${catData.restaurantSlug}-${catData.title}`, category);
File diff suppressed because it is too large Load Diff