feat: Phase 4 — 9 new features (v1.1)
Some checks failed
CI / Build & test backend (push) Failing after 14m56s

REQ-MOB-010: BarcodeScreen.tsx — barcode scanner via react-native-camera
REQ-VIZ-001: WeeklyCalorieChart.tsx — 7-day bar chart on History screen
REQ-VIZ-002: Streak tracker — GET /meals/streak + HomeScreen badge
REQ-UX-001: Quick-add calories — POST /meals/quick-add + QuickAddScreen
REQ-UX-002: Food favourites — UserFoodMemory.favourite + toggle endpoint + FoodRow star
REQ-UX-003: GoalBanner.tsx — in-app slide-in when daily target hit
REQ-EXP-001: ExportController — GET /export/meals CSV download
REQ-WTR-001: Water tracking — WaterEntry entity + POST/GET /water + DailyDetails widget
REQ-UX-004: Daily logging reminder — HomeScreen after-18:00 banner

Also: Flyway V2 (favourite), V3 (water_entries), V4 (source constraints)
Traceability, CHANGELOG, PLAN updated after each feature
This commit is contained in:
2026-05-19 02:11:23 +03:00
parent 904f1c43b3
commit 12820632e7
46 changed files with 8151 additions and 63 deletions

View File

@@ -92,6 +92,12 @@ export const searchFoods = (query: string) =>
export const getFoodByBarcode = (code: string) =>
api.get<FoodItem>(`/foods/barcode/${encodeURIComponent(code)}`);
export const getFavourites = () =>
api.get<FoodItem[]>('/foods/favourites');
export const toggleFavourite = (foodId: string) =>
api.post<{ favourite: boolean }>(`/foods/${encodeURIComponent(foodId)}/favourite`);
// Meals
export const getDailyOverview = (date: string) =>
api.get<DailyOverview>('/meals/daily', { params: { date } });
@@ -105,6 +111,12 @@ export const createMeal = (payload: object) =>
export const deleteMeal = (id: string) =>
api.delete(`/meals/${encodeURIComponent(id)}`);
export const getStreak = () =>
api.get<{ currentStreak: number; longestStreak: number }>('/meals/streak');
export const quickAddCalories = (payload: { date: string; mealType: string; calories: number; label?: string }) =>
api.post<MealEntry>('/meals/quick-add', payload);
// AI
export const analyzeMealPhoto = (imageFormData: FormData) =>
api.post<AiAnalysisResponse>('/ai/analyze-meal', imageFormData, {
@@ -114,4 +126,14 @@ export const analyzeMealPhoto = (imageFormData: FormData) =>
export const saveAiCorrections = (analysisId: string, corrections: { name: string; correctedGrams: number }[]) =>
api.post('/ai/correction', { analysisId, corrections });
export const exportMeals = (from: string, to: string) =>
api.get('/export/meals', { params: { from, to }, responseType: 'blob' });
// Water
export const getWaterDaily = (date: string) =>
api.get<{ date: string; totalMl: number }>('/water/daily', { params: { date } });
export const logWater = (date: string, amountMl: number) =>
api.post<{ date: string; totalMl: number }>('/water', { date, amountMl });
export default api;