krona-front/src/features/operations/RecipesView.tsx

131 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState } from 'react';
import { INITIAL_RECIPES, RecipeItem } from '../../mock/mockData';
import { Badge } from '../../shared/components/Badge';
import { Button } from '../../shared/components/Button';
import { formatCurrency } from '../../shared/utils/formatters';
import { ChefHat } from 'lucide-react';
import { Modal } from '../../shared/components/Modal';
export const RecipesView: React.FC = () => {
const [recipes] = useState<RecipeItem[]>(INITIAL_RECIPES);
const [selectedRecipe, setSelectedRecipe] = useState<RecipeItem | null>(null);
return (
<div className="space-y-4 animate-fade-in">
<div className="flex items-center justify-between bg-krona-surface p-3.5 rounded-xl border border-krona-border shadow-krona-soft">
<div>
<h2 className="text-sm font-bold text-krona-primary">
Технологические карты & Калькуляция (BOM)
</h2>
<p className="text-xs text-krona-secondary">
Нормы расхода сырья, расчет food cost %, плановая себестоимость и маржинальность
</p>
</div>
<Button variant="primary" size="sm" onClick={() => setSelectedRecipe(recipes[0])}>
<ChefHat className="w-3.5 h-3.5 mr-1.5" />
Посмотреть калькуляцию
</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{recipes.map((rec) => (
<div
key={rec.id}
onClick={() => setSelectedRecipe(rec)}
className="p-4 rounded-xl border border-krona-border bg-krona-surface hover:border-krona-border-strong shadow-krona-soft cursor-pointer transition-all space-y-3"
>
<div className="flex items-center justify-between">
<div>
<h4 className="text-sm font-bold text-krona-primary">{rec.name}</h4>
<span className="text-xs text-krona-secondary">Выход: {rec.yieldWeight} • {rec.category}</span>
</div>
<Badge variant="green" size="sm">Food Cost: {rec.foodCostPercent}%</Badge>
</div>
<div className="grid grid-cols-3 gap-2 p-2.5 rounded-lg bg-krona-workspace text-xs">
<div>
<span className="text-krona-secondary block text-[10px]">Себестоимость:</span>
<span className="font-bold text-krona-primary">{formatCurrency(rec.primeCost)}</span>
</div>
<div>
<span className="text-krona-secondary block text-[10px]">Цена продажи:</span>
<span className="font-bold text-krona-green">{formatCurrency(rec.sellingPrice)}</span>
</div>
<div>
<span className="text-krona-secondary block text-[10px]">Маржа (руб):</span>
<span className="font-bold text-krona-gold">{formatCurrency(rec.marginRub)}</span>
</div>
</div>
<div className="text-xs text-krona-secondary">
<span className="font-medium text-krona-primary">Ингредиенты ({rec.ingredients.length}): </span>
{rec.ingredients.map((i) => i.name).join(', ')}
</div>
</div>
))}
</div>
{/* Recipe Detail Modal */}
{selectedRecipe && (
<Modal
isOpen={Boolean(selectedRecipe)}
onClose={() => setSelectedRecipe(null)}
title={`Техкарта: ${selectedRecipe.name}`}
subtitle={`Выход готового блюда: ${selectedRecipe.yieldWeight}`}
maxWidth="lg"
footer={
<Button variant="secondary" onClick={() => setSelectedRecipe(null)}>
Закрыть
</Button>
}
>
<div className="space-y-4 text-xs">
<div className="grid grid-cols-4 gap-2 p-3 bg-krona-workspace rounded-lg text-center">
<div>
<span className="text-krona-secondary block text-[10px]">Цена в меню:</span>
<span className="font-bold text-sm text-krona-primary">{formatCurrency(selectedRecipe.sellingPrice)}</span>
</div>
<div>
<span className="text-krona-secondary block text-[10px]">Себестоимость:</span>
<span className="font-bold text-sm text-krona-danger">{formatCurrency(selectedRecipe.primeCost)}</span>
</div>
<div>
<span className="text-krona-secondary block text-[10px]">Food Cost %:</span>
<span className="font-bold text-sm text-krona-green">{selectedRecipe.foodCostPercent}%</span>
</div>
<div>
<span className="text-krona-secondary block text-[10px]">Маржинальный доход:</span>
<span className="font-bold text-sm text-krona-gold">{formatCurrency(selectedRecipe.marginRub)}</span>
</div>
</div>
<div>
<h5 className="font-semibold text-krona-primary mb-2">Расход сырья и калькуляция:</h5>
<table className="w-full text-left border-collapse">
<thead>
<tr className="border-b border-krona-border text-krona-secondary text-[11px]">
<th className="pb-1.5 font-medium">Ингредиент</th>
<th className="pb-1.5 font-medium">Брутто</th>
<th className="pb-1.5 font-medium">Нетто</th>
<th className="pb-1.5 font-medium text-right">Стоимость</th>
</tr>
</thead>
<tbody className="divide-y divide-krona-border/40">
{selectedRecipe.ingredients.map((ing, i) => (
<tr key={i} className="py-1.5">
<td className="py-1.5 font-medium text-krona-primary">{ing.name}</td>
<td className="py-1.5 text-krona-secondary">{ing.gross}</td>
<td className="py-1.5 text-krona-secondary">{ing.net}</td>
<td className="py-1.5 font-semibold text-right text-krona-primary">{formatCurrency(ing.cost)}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</Modal>
)}
</div>
);
};