Advertisement
Richbadniss

Tile Comparison Component

Dec 1st, 2024
22
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { Card} from "./card"
  2. import { Button } from "./button"
  3. import { Star } from "lucide-react"
  4. import { TileOption } from "@/types/types";
  5.  
  6. interface TileComparisonProps {
  7.   options: TileOption[];
  8.   roomArea: number;
  9.   onSelectOption: (option: TileOption) => void;
  10. }
  11.  
  12. export function TileComparison({ options, roomArea, onSelectOption }: TileComparisonProps) {
  13.   const calculateTotalCost = (option: TileOption) => {
  14.     const areaInSqFt = roomArea * 10.764;  // convert m² to ft²
  15.     const laborCost = areaInSqFt * option.laborCostPerSqFt;
  16.     const tilesNeeded = Math.ceil((roomArea * 10000) / (option.size * 2.54) ** 2 * 1.1);
  17.     const materialCost = tilesNeeded * option.cost;
  18.     return { laborCost, materialCost, total: laborCost + materialCost };
  19.   };
  20.  
  21.   const getBestOption = () => {
  22.     return options.reduce((best, current) => {
  23.       const currentCost = calculateTotalCost(current).total;
  24.       const bestCost = calculateTotalCost(best).total;
  25.       const currentScore = current.durability + current.aestheticRating + current.maintenanceRating - (currentCost / 1000);
  26.       const bestScore = best.durability + best.aestheticRating + best.maintenanceRating - (bestCost / 1000);
  27.       return currentScore > bestScore ? current : best;
  28.     }, options[0]);
  29.   };
  30.  
  31.   const renderRatingBar = (rating: number) => (
  32.     <div className="h-2 w-full bg-gray-100 rounded-full overflow-hidden">
  33.       <div
  34.         className="h-full bg-blue-500 transition-all duration-300"
  35.         style={{ width: `${rating * 10}%` }}
  36.       />
  37.     </div>
  38.   );
  39.  
  40.   return (
  41.     <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
  42.       {options.map((option, index) => {
  43.         const costs = calculateTotalCost(option);
  44.         const isRecommended = option === getBestOption();
  45.  
  46.         return (
  47.           <Card
  48.             key={index}
  49.             className={`relative p-6 rounded-xl transition-transform duration-300 hover:scale-105 ${
  50.               isRecommended ? 'ring-2 ring-blue-500' : 'ring-1 ring-gray-200'
  51.             }`}
  52.           >
  53.             {isRecommended && (
  54.               <div className="absolute -top-3 left-1/2 -translate-x-1/2">
  55.                 <div className="flex items-center gap-1 bg-blue-500 text-white px-3 py-1 rounded-full text-sm">
  56.                   <Star className="w-4 h-4" />
  57.                   <span>Best Choice</span>
  58.                 </div>
  59.               </div>
  60.             )}
  61.  
  62.             <div className="mb-6">
  63.               <h3 className="text-2xl font-bold mb-1">{option.name}</h3>
  64.               <p className="text-gray-500">{option.size}″ × {option.size}″ tiles</p>
  65.             </div>
  66.  
  67.             <div className="space-y-6">
  68.               {/* Costs */}
  69.               <div className="space-y-3">
  70.                 <div className="flex justify-between">
  71.                   <span className="text-gray-500">Material Cost</span>
  72.                   <span className="font-medium">
  73.                     ${costs.materialCost.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
  74.                   </span>
  75.                 </div>
  76.                 <div className="flex justify-between">
  77.                   <span className="text-gray-500">Labor Cost</span>
  78.                   <span className="font-medium">
  79.                     ${costs.laborCost.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
  80.                   </span>
  81.                 </div>
  82.                 <div className="pt-3 border-t border-gray-100">
  83.                   <div className="flex justify-between items-baseline">
  84.                     <span className="font-medium">Total Cost</span>
  85.                     <span className="text-xl font-bold">
  86.                       ${costs.total.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
  87.                     </span>
  88.                   </div>
  89.                 </div>
  90.               </div>
  91.  
  92.               {/* Ratings */}
  93.               <div className="space-y-4">
  94.                 <div className="space-y-2">
  95.                   <div className="flex justify-between">
  96.                     <span className="text-gray-500">Durability</span>
  97.                     <span className="text-sm font-medium">{option.durability}/10</span>
  98.                   </div>
  99.                   {renderRatingBar(option.durability)}
  100.                 </div>
  101.  
  102.                 <div className="space-y-2">
  103.                   <div className="flex justify-between">
  104.                     <span className="text-gray-500">Aesthetics</span>
  105.                     <span className="text-sm font-medium">{option.aestheticRating}/10</span>
  106.                   </div>
  107.                   {renderRatingBar(option.aestheticRating)}
  108.                 </div>
  109.  
  110.                 <div className="space-y-2">
  111.                   <div className="flex justify-between">
  112.                     <span className="text-gray-500">Maintenance</span>
  113.                     <span className="text-sm font-medium">{option.maintenanceRating}/10</span>
  114.                   </div>
  115.                   {renderRatingBar(option.maintenanceRating)}
  116.                 </div>
  117.               </div>
  118.  
  119.               <Button
  120.                 onClick={() => onSelectOption(option)}
  121.                 className={`w-full py-6 rounded-xl ${
  122.                   isRecommended
  123.                     ? 'bg-blue-500 hover:bg-blue-600'
  124.                     : 'bg-gray-900 hover:bg-gray-800'
  125.                 }`}
  126.               >
  127.                 Select {option.name}
  128.               </Button>
  129.             </div>
  130.           </Card>
  131.         );
  132.       })}
  133.     </div>
  134.   );
  135. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement