feat(ui): enhance footer with NutriScan branding and fix database path
- Redesigned Footer.tsx with comprehensive layout including brand section, navigation links, social media icons, and contact info to improve user engagement and brand visibility - Updated DATABASE_URL in .env to correct Prisma database path for proper configuration and connectivity - Updated dependencies to support new UI components and ensure compatibility with enhanced features
This commit is contained in:
1 parent
8d6cbeb0bb
commit
9a4e4c762e
51 files changed
+7389
-218
No files matched your search
@@ -0,0 +1,283 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
CheckCircle2,
|
||||
XCircle,
|
||||
Zap,
|
||||
BarChart3,
|
||||
GitCompare,
|
||||
Download,
|
||||
Code,
|
||||
MessageSquare,
|
||||
Shield,
|
||||
} from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
|
||||
interface Feature {
|
||||
text: string;
|
||||
included: boolean;
|
||||
highlight?: boolean;
|
||||
note?: string;
|
||||
}
|
||||
|
||||
interface PricingCardProps {
|
||||
plan: "basic" | "premium" | "free";
|
||||
isAnnual?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const planData = {
|
||||
basic: {
|
||||
name: "Básico",
|
||||
monthlyPrice: 5,
|
||||
annualPrice: 4,
|
||||
description: "Perfeito para uso pessoal e pequenas consultas",
|
||||
badge: null,
|
||||
features: [
|
||||
{ text: "Até 100 consultas/mês", included: true },
|
||||
{ text: "Busca por código de barras", included: true },
|
||||
{ text: "Busca por nome", included: true },
|
||||
{ text: "Informações nutricionais completas", included: true },
|
||||
{ text: "Histórico (últimas 10)", included: true },
|
||||
{ text: "Filtros avançados", included: false },
|
||||
{ text: "Listas de compras", included: false },
|
||||
{ text: "Comparação de produtos", included: false },
|
||||
{ text: "Exportação de dados", included: false },
|
||||
{ text: "API de acesso", included: false },
|
||||
{ text: "Suporte prioritário", included: false },
|
||||
],
|
||||
},
|
||||
premium: {
|
||||
name: "Premium",
|
||||
monthlyPrice: 10,
|
||||
annualPrice: 8,
|
||||
description: "Ideal para profissionais e uso intensivo",
|
||||
badge: "Popular",
|
||||
features: [
|
||||
{ text: "Até 500 consultas/mês", included: true },
|
||||
{ text: "Busca por código de barras", included: true },
|
||||
{ text: "Busca por nome", included: true },
|
||||
{ text: "Informações nutricionais completas", included: true },
|
||||
{ text: "Histórico ilimitado", included: true },
|
||||
{ text: "Filtros avançados", included: true },
|
||||
{ text: "Listas de compras ilimitadas", included: true },
|
||||
{ text: "Comparação de produtos (até 5)", included: true },
|
||||
{ text: "Exportação de dados (CSV/JSON)", included: true },
|
||||
{ text: "API de acesso (1000 req/mês)", included: true },
|
||||
{ text: "Suporte prioritário", included: true },
|
||||
],
|
||||
},
|
||||
free: {
|
||||
name: "Free Beta",
|
||||
monthlyPrice: 0,
|
||||
annualPrice: 0,
|
||||
description: "Acesso completo durante fase beta",
|
||||
badge: "Beta",
|
||||
features: [
|
||||
{ text: "Consultas ilimitadas", included: true, highlight: true },
|
||||
{ text: "Busca por código de barras", included: true },
|
||||
{ text: "Busca por nome", included: true },
|
||||
{ text: "Informações nutricionais completas", included: true },
|
||||
{ text: "Histórico ilimitado", included: true },
|
||||
{ text: "Filtros avançados", included: true },
|
||||
{ text: "Listas de compras ilimitadas", included: true },
|
||||
{ text: "Comparação de produtos", included: true },
|
||||
{ text: "Exportação de dados", included: true },
|
||||
{ text: "Badge Beta Tester", included: true, highlight: true },
|
||||
{ text: "Acesso temporário", included: true, note: "Durante fase beta" },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const featureIcons: Record<string, any> = {
|
||||
consultas: Zap,
|
||||
filtros: BarChart3,
|
||||
comparação: GitCompare,
|
||||
exportação: Download,
|
||||
api: Code,
|
||||
suporte: MessageSquare,
|
||||
beta: Shield,
|
||||
};
|
||||
|
||||
export function PricingCard({
|
||||
plan,
|
||||
isAnnual = false,
|
||||
className = "",
|
||||
}: PricingCardProps) {
|
||||
const data = planData[plan];
|
||||
const price = isAnnual ? data.annualPrice : data.monthlyPrice;
|
||||
const isPopular = plan === "premium";
|
||||
const isFree = plan === "free";
|
||||
|
||||
const getFeatureIcon = (featureText: string) => {
|
||||
if (featureText.includes("consultas") || featureText.includes("API"))
|
||||
return Zap;
|
||||
if (featureText.includes("filtros")) return BarChart3;
|
||||
if (featureText.includes("comparação")) return GitCompare;
|
||||
if (featureText.includes("exportação")) return Download;
|
||||
if (featureText.includes("suporte")) return MessageSquare;
|
||||
if (featureText.includes("Beta")) return Shield;
|
||||
return CheckCircle2;
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={`relative overflow-hidden transition-all duration-300 hover:shadow-xl ${
|
||||
isPopular
|
||||
? "bg-gradient-to-br from-blue-600 to-blue-700 text-white scale-105 border-2 border-blue-500 shadow-2xl"
|
||||
: isFree
|
||||
? "border-blue-200 dark:border-blue-800 bg-white dark:bg-gray-900"
|
||||
: "bg-white dark:bg-gray-900 border-gray-100 dark:border-gray-800"
|
||||
} ${className}`}
|
||||
>
|
||||
{/* Badge */}
|
||||
{data.badge && (
|
||||
<div className="absolute top-0 right-0">
|
||||
<Badge
|
||||
className={`${
|
||||
isPopular
|
||||
? "bg-[#19A7A7] text-white"
|
||||
: isFree
|
||||
? "bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300"
|
||||
: "bg-gray-100 text-gray-700"
|
||||
} rounded-l-none rounded-br-lg`}
|
||||
>
|
||||
{data.badge}
|
||||
</Badge>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<CardHeader className="pb-4">
|
||||
<div className="text-center">
|
||||
<h3
|
||||
className={`text-2xl font-bold ${
|
||||
isPopular ? "text-white" : "text-gray-900 dark:text-white"
|
||||
}`}
|
||||
>
|
||||
{data.name}
|
||||
</h3>
|
||||
<p
|
||||
className={`text-sm mt-2 ${
|
||||
isPopular ? "text-blue-100" : "text-gray-600 dark:text-gray-400"
|
||||
}`}
|
||||
>
|
||||
{data.description}
|
||||
</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="space-y-6">
|
||||
{/* Preço */}
|
||||
<div className="text-center">
|
||||
<div className="flex items-baseline justify-center">
|
||||
<span
|
||||
className={`text-5xl font-bold ${
|
||||
isPopular ? "text-white" : "text-gray-900 dark:text-white"
|
||||
}`}
|
||||
>
|
||||
${price}
|
||||
</span>
|
||||
{!isFree && (
|
||||
<span
|
||||
className={`text-sm ml-1 ${
|
||||
isPopular ? "text-blue-100" : "text-gray-500"
|
||||
}`}
|
||||
>
|
||||
/mês
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{isAnnual && !isFree && (
|
||||
<p
|
||||
className={`text-xs mt-1 ${
|
||||
isPopular ? "text-blue-100" : "text-green-600"
|
||||
}`}
|
||||
>
|
||||
Economize ${(data.monthlyPrice - data.annualPrice) * 12}/ano
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Botões */}
|
||||
<div className="space-y-3">
|
||||
<Button
|
||||
className={`w-full ${
|
||||
isPopular
|
||||
? "bg-[#19A7A7] hover:bg-teal-600 text-white"
|
||||
: isFree
|
||||
? "bg-[#0055FF] hover:bg-blue-600 text-white"
|
||||
: "bg-[#0055FF] hover:bg-blue-600 text-white"
|
||||
}`}
|
||||
size="lg"
|
||||
>
|
||||
{isFree ? "Começar Grátis" : "Começar Agora"}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={`w-full ${
|
||||
isPopular
|
||||
? "border-blue-400 text-blue-100 hover:bg-blue-500/20"
|
||||
: "border-gray-300 text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
>
|
||||
Falar com Vendas
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Features */}
|
||||
<div className="space-y-3">
|
||||
{data.features.map((feature, index) => {
|
||||
const IconComponent = getFeatureIcon(feature.text);
|
||||
return (
|
||||
<div key={index} className="flex items-start space-x-3">
|
||||
<div className="flex-shrink-0 mt-0.5">
|
||||
{feature.included ? (
|
||||
<CheckCircle2
|
||||
className={`w-4 h-4 ${
|
||||
feature.highlight
|
||||
? "text-green-500"
|
||||
: isPopular
|
||||
? "text-green-400"
|
||||
: "text-green-500"
|
||||
}`}
|
||||
/>
|
||||
) : (
|
||||
<XCircle
|
||||
className={`w-4 h-4 ${
|
||||
isPopular ? "text-red-400" : "text-gray-400"
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<span
|
||||
className={`text-sm ${
|
||||
feature.highlight
|
||||
? "font-semibold text-green-600 dark:text-green-400"
|
||||
: isPopular
|
||||
? "text-white"
|
||||
: "text-gray-700 dark:text-gray-300"
|
||||
}`}
|
||||
>
|
||||
{feature.text}
|
||||
</span>
|
||||
{feature.note && (
|
||||
<p
|
||||
className={`text-xs mt-1 ${
|
||||
isPopular ? "text-blue-100" : "text-gray-500"
|
||||
}`}
|
||||
>
|
||||
{feature.note}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user