refactor food service
This commit is contained in:
@@ -110,59 +110,75 @@ export class FoodService {
|
|||||||
return food;
|
return food;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find active foods for a restaurant based on current week day and meal type in Iran timezone.
|
||||||
|
* @param slug - Restaurant slug identifier
|
||||||
|
* @returns Array of active foods matching current day and meal time
|
||||||
|
*/
|
||||||
async findByWeekDateAndMealType(slug: string): Promise<Food[]> {
|
async findByWeekDateAndMealType(slug: string): Promise<Food[]> {
|
||||||
// const cacheKey = `${this.FOODS_BY_RESTAURANT_CACHE_KEY_PREFIX}${slug}`;
|
|
||||||
|
|
||||||
// Try to get from cache first
|
|
||||||
// const cachedFoods = await this.cacheService.get<string>(cacheKey);
|
|
||||||
// if (cachedFoods) {
|
|
||||||
// try {
|
|
||||||
// const parsed: unknown = JSON.parse(cachedFoods);
|
|
||||||
// if (Array.isArray(parsed)) {
|
|
||||||
// return parsed as Food[];
|
|
||||||
// }
|
|
||||||
// } catch {
|
|
||||||
// // If parsing fails, continue to fetch from DB
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// If not in cache, fetch from database
|
|
||||||
const restaurant = await this.restRepository.findOne({ slug });
|
const restaurant = await this.restRepository.findOne({ slug });
|
||||||
if (!restaurant) {
|
if (!restaurant) {
|
||||||
throw new NotFoundException(RestMessage.NOT_FOUND);
|
throw new NotFoundException(RestMessage.NOT_FOUND);
|
||||||
}
|
}
|
||||||
const nowInIran = new Date(new Date().toLocaleString('en-US', { timeZone: 'Asia/Tehran' }));
|
|
||||||
|
|
||||||
|
const { iranWeekDay, mealType } = this.getCurrentIranTimeContext();
|
||||||
|
|
||||||
|
const queryFilter: FilterQuery<Food> = {
|
||||||
|
restaurant: { slug },
|
||||||
|
isActive: true,
|
||||||
|
weekDays: { $contains: iranWeekDay },
|
||||||
|
...(mealType ? { mealTypes: { $contains: mealType } } : {}),
|
||||||
|
} as unknown as FilterQuery<Food>;
|
||||||
|
|
||||||
|
return this.foodRepository.find(queryFilter, { populate: ['category'] });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current Iran timezone context (weekday and meal type).
|
||||||
|
* @returns Object containing Iran weekday (0-6, where 0=Saturday) and current meal type
|
||||||
|
*/
|
||||||
|
private getCurrentIranTimeContext(): { iranWeekDay: number; mealType: MealType | null } {
|
||||||
|
const nowInIran = new Date(new Date().toLocaleString('en-US', { timeZone: 'Asia/Tehran' }));
|
||||||
const weekDay = nowInIran.getDay(); // 0 = Sunday, 6 = Saturday
|
const weekDay = nowInIran.getDay(); // 0 = Sunday, 6 = Saturday
|
||||||
const currentHour = nowInIran.getHours();
|
const currentHour = nowInIran.getHours();
|
||||||
|
|
||||||
|
// Convert to Iran weekday: Saturday=0, Sunday=1, ..., Friday=6
|
||||||
|
// JavaScript: Sunday=0, Monday=1, ..., Saturday=6
|
||||||
|
// Iran week: Saturday=0, Sunday=1, ..., Friday=6
|
||||||
const iranWeekDay = (weekDay + 1) % 7;
|
const iranWeekDay = (weekDay + 1) % 7;
|
||||||
|
|
||||||
let mealType: string | null = null;
|
const mealType = this.getMealTypeByHour(currentHour);
|
||||||
if (currentHour >= 6 && currentHour < 11) {
|
|
||||||
mealType = MealType.BREAKFAST;
|
return { iranWeekDay, mealType };
|
||||||
} else if (currentHour >= 11 && currentHour < 15) {
|
|
||||||
mealType = MealType.LUNCH;
|
|
||||||
} else if (currentHour >= 15 && currentHour < 19) {
|
|
||||||
mealType = MealType.SNACK;
|
|
||||||
} else if (currentHour >= 19 && currentHour < 24) {
|
|
||||||
mealType = MealType.DINNER;
|
|
||||||
}
|
}
|
||||||
const foods = await this.foodRepository.find(
|
|
||||||
// cast to FilterQuery<Food> because MikroORM types don't accept a numeric $contains value for jsonb number[]
|
|
||||||
{
|
|
||||||
restaurant: { slug },
|
|
||||||
isActive: true,
|
|
||||||
...(mealType ? { mealTypes: { $contains: mealType } } : {}),
|
|
||||||
weekDays: { $contains: iranWeekDay },
|
|
||||||
} as unknown as FilterQuery<Food>,
|
|
||||||
{ populate: ['category'] },
|
|
||||||
);
|
|
||||||
|
|
||||||
// Cache the result
|
/**
|
||||||
// await this.cacheService.set(cacheKey, JSON.stringify(foods), this.FOODS_CACHE_TTL);
|
* Determine meal type based on current hour in Iran timezone.
|
||||||
|
* @param hour - Current hour (0-23)
|
||||||
|
* @returns Meal type or null if outside meal hours
|
||||||
|
*/
|
||||||
|
private getMealTypeByHour(hour: number): MealType | null {
|
||||||
|
const MEAL_TIME_RANGES = {
|
||||||
|
BREAKFAST: { start: 6, end: 11 },
|
||||||
|
LUNCH: { start: 11, end: 15 },
|
||||||
|
SNACK: { start: 15, end: 19 },
|
||||||
|
DINNER: { start: 19, end: 24 },
|
||||||
|
} as const;
|
||||||
|
|
||||||
return foods;
|
if (hour >= MEAL_TIME_RANGES.BREAKFAST.start && hour < MEAL_TIME_RANGES.BREAKFAST.end) {
|
||||||
|
return MealType.BREAKFAST;
|
||||||
|
}
|
||||||
|
if (hour >= MEAL_TIME_RANGES.LUNCH.start && hour < MEAL_TIME_RANGES.LUNCH.end) {
|
||||||
|
return MealType.LUNCH;
|
||||||
|
}
|
||||||
|
if (hour >= MEAL_TIME_RANGES.SNACK.start && hour < MEAL_TIME_RANGES.SNACK.end) {
|
||||||
|
return MealType.SNACK;
|
||||||
|
}
|
||||||
|
if (hour >= MEAL_TIME_RANGES.DINNER.start && hour < MEAL_TIME_RANGES.DINNER.end) {
|
||||||
|
return MealType.DINNER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(restId: string, id: string, dto: Partial<CreateFoodDto>): Promise<Food> {
|
async update(restId: string, id: string, dto: Partial<CreateFoodDto>): Promise<Food> {
|
||||||
|
|||||||
Reference in New Issue
Block a user