2025-12-26 14:03:18 +01:00
|
|
|
|
2025-12-21 20:40:32 +01:00
|
|
|
import React, { useState, useEffect } from 'react';
|
2025-12-26 14:03:18 +01:00
|
|
|
import { Check, Star, ShieldCheck, Clock, Info } from 'lucide-react';
|
2025-12-21 20:40:32 +01:00
|
|
|
import { Button } from '../components/Button';
|
|
|
|
|
import { Link } from 'react-router-dom';
|
|
|
|
|
import { supabase } from '../lib/supabaseClient';
|
|
|
|
|
import { ProductPackage } from '../types';
|
|
|
|
|
import { defaultPlans } from '../lib/defaultPlans';
|
|
|
|
|
|
|
|
|
|
export const Products: React.FC = () => {
|
|
|
|
|
const [packages, setPackages] = useState<ProductPackage[]>(defaultPlans);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const fetchPlans = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('plans')
|
2025-12-26 14:03:18 +01:00
|
|
|
.select('*');
|
2025-12-21 20:40:32 +01:00
|
|
|
|
|
|
|
|
if (!error && data && data.length > 0) {
|
2025-12-26 14:03:18 +01:00
|
|
|
const sortedData = [...data].sort((a, b) => {
|
|
|
|
|
const priceA = a.is_custom_price ? Infinity : (a.total_price || 0);
|
|
|
|
|
const priceB = b.is_custom_price ? Infinity : (b.total_price || 0);
|
|
|
|
|
return priceA - priceB;
|
|
|
|
|
});
|
|
|
|
|
setPackages(sortedData);
|
|
|
|
|
} else {
|
|
|
|
|
const sortedDefaults = [...defaultPlans].sort((a, b) => {
|
|
|
|
|
const priceA = a.is_custom_price ? Infinity : (a.total_price || 0);
|
|
|
|
|
const priceB = b.is_custom_price ? Infinity : (b.total_price || 0);
|
|
|
|
|
return priceA - priceB;
|
|
|
|
|
});
|
|
|
|
|
setPackages(sortedDefaults);
|
2025-12-21 20:40:32 +01:00
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error("Error fetching plans:", e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
fetchPlans();
|
|
|
|
|
}, []);
|
|
|
|
|
|
2025-12-26 14:03:18 +01:00
|
|
|
const formatPrice = (num: number) => num.toLocaleString('hu-HU') + ' Ft';
|
|
|
|
|
|
2025-12-21 20:40:32 +01:00
|
|
|
return (
|
|
|
|
|
<div className="pt-20 bg-gray-50 min-h-screen">
|
|
|
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
|
|
|
|
|
<div className="text-center mb-16">
|
|
|
|
|
<h1 className="text-4xl font-extrabold text-gray-900 mb-4">Csomagajánlataink</h1>
|
|
|
|
|
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
|
|
|
|
Átlátható árazás, rejtett költségek nélkül. Válassza az Ön céljaihoz leginkább illeszkedő csomagot.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
2025-12-26 14:03:18 +01:00
|
|
|
{packages.map((pkg, index) => {
|
|
|
|
|
const remaining = (pkg.total_price || 0) - (pkg.advance_price || 0);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
key={index}
|
|
|
|
|
className={`relative bg-white rounded-2xl shadow-xl flex flex-col p-8 transition-transform hover:-translate-y-2 duration-300 ${pkg.isPopular ? 'border-2 border-primary ring-4 ring-purple-100' : 'border border-gray-100'}`}
|
|
|
|
|
>
|
|
|
|
|
{pkg.isPopular && (
|
|
|
|
|
<div className="absolute top-0 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-gradient-to-r from-primary to-secondary text-white px-4 py-1 rounded-full text-sm font-bold shadow-lg flex items-center gap-1">
|
|
|
|
|
<Star className="w-4 h-4 fill-current" /> Legnépszerűbb
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<div className="mb-6">
|
|
|
|
|
<h3 className="text-2xl font-bold text-gray-900">{pkg.name}</h3>
|
|
|
|
|
<p className="text-gray-500 mt-2 text-sm min-h-[40px]">{pkg.desc}</p>
|
2025-12-21 20:40:32 +01:00
|
|
|
</div>
|
|
|
|
|
|
2025-12-26 14:03:18 +01:00
|
|
|
<div className="mb-8">
|
|
|
|
|
<span className="text-3xl font-extrabold text-gray-900 block">
|
|
|
|
|
{pkg.is_custom_price ? 'Egyedi árazás' : (pkg.price || 'Egyedi árazás')}
|
|
|
|
|
</span>
|
|
|
|
|
{!pkg.is_custom_price && pkg.advance_price && pkg.advance_price > 0 ? (
|
|
|
|
|
<div className="mt-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
|
|
|
|
<p className="text-xs font-bold text-gray-400 uppercase tracking-widest mb-1 text-center border-b border-gray-200 pb-1">Fizetési ütemezés</p>
|
|
|
|
|
<div className="mt-2 space-y-1">
|
|
|
|
|
<p className="text-sm font-bold text-gray-700 flex justify-between"><span>Előleg:</span> <span>{formatPrice(pkg.advance_price)}</span></p>
|
|
|
|
|
<p className="text-sm font-medium text-gray-500 flex flex-col pt-1 border-t border-gray-100 mt-1">
|
|
|
|
|
<span className="text-[10px] font-bold text-primary uppercase">Demó elfogadása után:</span>
|
|
|
|
|
<span className="font-bold text-gray-700">{formatPrice(remaining)}</span>
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
|
|
|
|
</div>
|
2025-12-21 20:40:32 +01:00
|
|
|
|
2025-12-26 14:03:18 +01:00
|
|
|
<ul className="space-y-4 mb-8 flex-grow">
|
|
|
|
|
{pkg.features.map((feature, i) => (
|
|
|
|
|
<li key={i} className="flex items-start text-gray-600">
|
|
|
|
|
<Check className="w-5 h-5 text-green-500 mr-3 flex-shrink-0 mt-0.5" />
|
|
|
|
|
<span className="text-sm">{feature}</span>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
2025-12-21 20:40:32 +01:00
|
|
|
|
2025-12-26 14:03:18 +01:00
|
|
|
<div className="mt-auto">
|
|
|
|
|
<Link to="/contact">
|
|
|
|
|
<Button
|
|
|
|
|
variant={pkg.isPopular ? 'primary' : 'outline'}
|
|
|
|
|
fullWidth
|
|
|
|
|
>
|
|
|
|
|
{pkg.cta}
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
2025-12-21 20:40:32 +01:00
|
|
|
</div>
|
2025-12-26 14:03:18 +01:00
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Maintenance Info Panel */}
|
|
|
|
|
<div className="mt-12 w-full">
|
|
|
|
|
<div className="bg-white border border-gray-200 rounded-[32px] p-6 md:p-10 shadow-sm flex flex-col md:flex-row items-center gap-6 md:gap-10">
|
|
|
|
|
<div className="w-16 h-16 md:w-20 md:h-20 bg-primary/5 rounded-3xl flex items-center justify-center text-primary shrink-0 border border-primary/10">
|
|
|
|
|
<ShieldCheck className="w-8 h-8 md:w-10 md:h-10" />
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex-grow text-center md:text-left">
|
|
|
|
|
<h4 className="text-lg md:text-xl font-bold text-gray-900 mb-2 uppercase tracking-tight">Éves üzemeltetés és karbantartás</h4>
|
|
|
|
|
<p className="text-sm md:text-base text-gray-600 leading-relaxed mb-4">
|
|
|
|
|
Minden csomagunkhoz egységes, kedvező üzemeltetési díj tartozik, amely tartalmazza a tárhelyet, a biztonsági mentéseket és a folyamatos monitorozást. <strong>A csomagár tartalmazza az első év üzemeltetését, így az első éves díj megfizetése csak a projekt átadását követő egy év múlva válik esedékessé.</strong>
|
|
|
|
|
</p>
|
|
|
|
|
<div className="flex flex-wrap justify-center md:justify-start gap-4 text-[10px] md:text-xs font-bold uppercase tracking-widest text-gray-400">
|
|
|
|
|
<span className="flex items-center gap-1.5"><Clock className="w-3.5 h-3.5 text-primary" /> 2026-ig rögzített ár</span>
|
|
|
|
|
<span className="flex items-center gap-1.5"><Info className="w-3.5 h-3.5 text-primary" /> Éves inflációkövető korrekció lehetséges</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="bg-primary text-white rounded-[24px] px-8 py-6 text-center shadow-xl shadow-primary/20 min-w-[220px]">
|
|
|
|
|
<p className="text-[10px] font-bold opacity-70 uppercase tracking-[0.2em] mb-1">Éves Fenntartás</p>
|
|
|
|
|
<p className="text-2xl md:text-3xl font-black">59 990 Ft</p>
|
2025-12-21 20:40:32 +01:00
|
|
|
</div>
|
2025-12-26 14:03:18 +01:00
|
|
|
</div>
|
2025-12-21 20:40:32 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="mt-20 bg-white rounded-2xl p-8 md:p-12 shadow-sm border border-gray-100 flex flex-col md:flex-row items-center justify-between gap-8">
|
|
|
|
|
<div>
|
|
|
|
|
<h3 className="text-2xl font-bold text-gray-900 mb-2">Egyedi igényei vannak?</h3>
|
|
|
|
|
<p className="text-gray-600">
|
|
|
|
|
Nem találja a megfelelő csomagot? Készítünk Önnek egy teljesen személyre szabott ajánlatot.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<Link to="/contact">
|
|
|
|
|
<Button size="lg">Kapcsolatfelvétel</Button>
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|