-
-
Save pedroribeirodev/da377af5c366fbb32f1efee87731cf35 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The exported code uses Tailwind CSS. Install Tailwind CSS in your dev environment to ensure all styles work. | |
import React, { useState } from "react"; | |
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; | |
import { | |
Card, | |
CardContent, | |
CardDescription, | |
CardHeader, | |
CardTitle, | |
} from "@/components/ui/card"; | |
import { Button } from "@/components/ui/button"; | |
import { Input } from "@/components/ui/input"; | |
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; | |
import { Badge } from "@/components/ui/badge"; | |
import { ScrollArea } from "@/components/ui/scroll-area"; | |
import { | |
Select, | |
SelectContent, | |
SelectItem, | |
SelectTrigger, | |
SelectValue, | |
} from "@/components/ui/select"; | |
import { | |
Dialog, | |
DialogContent, | |
DialogDescription, | |
DialogHeader, | |
DialogTitle, | |
DialogTrigger, | |
} from "@/components/ui/dialog"; | |
import { Label } from "@/components/ui/label"; | |
import * as echarts from "echarts"; | |
import { useEffect } from "react"; | |
const App: React.FC = () => { | |
const [activeTab, setActiveTab] = useState("clientes"); | |
const [addClientOpen, setAddClientOpen] = useState(false); | |
const [importClientOpen, setImportClientOpen] = useState(false); | |
const [newClient, setNewClient] = useState({ | |
name: "", | |
email: "", | |
phone: "", | |
status: "Ativo", | |
}); | |
const [selectedFile, setSelectedFile] = useState<File | null>(null); | |
const handleAddClient = (e: React.FormEvent) => { | |
e.preventDefault(); | |
// Handle client addition logic here | |
console.log("New client:", newClient); | |
setNewClient({ name: "", email: "", phone: "", status: "Ativo" }); | |
setAddClientOpen(false); | |
}; | |
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { | |
if (e.target.files && e.target.files[0]) { | |
setSelectedFile(e.target.files[0]); | |
} | |
}; | |
const handleImportClients = (e: React.FormEvent) => { | |
e.preventDefault(); | |
// Handle file import logic here | |
console.log("Selected file:", selectedFile); | |
setSelectedFile(null); | |
setImportClientOpen(false); | |
}; | |
useEffect(() => { | |
// Vendas chart | |
const vendasChartElement = document.getElementById("vendas-chart"); | |
if (vendasChartElement) { | |
const vendasChart = echarts.init(vendasChartElement); | |
const vendasOption = { | |
animation: false, | |
tooltip: { | |
trigger: "axis", | |
}, | |
legend: { | |
data: ["Vendas", "Reativações"], | |
}, | |
grid: { | |
left: "3%", | |
right: "4%", | |
bottom: "3%", | |
containLabel: true, | |
}, | |
xAxis: { | |
type: "category", | |
boundaryGap: false, | |
data: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun"], | |
}, | |
yAxis: { | |
type: "value", | |
}, | |
series: [ | |
{ | |
name: "Vendas", | |
type: "line", | |
data: [120, 132, 101, 134, 90, 230], | |
color: "#8b5cf6", | |
}, | |
{ | |
name: "Reativações", | |
type: "line", | |
data: [20, 82, 91, 84, 110, 120], | |
color: "#22c55e", | |
}, | |
], | |
}; | |
vendasChart.setOption(vendasOption); | |
const handleResize = () => { | |
vendasChart.resize(); | |
}; | |
window.addEventListener("resize", handleResize); | |
return () => { | |
window.removeEventListener("resize", handleResize); | |
vendasChart.dispose(); | |
}; | |
} | |
// Pagamentos chart | |
const pagamentosChartElement = document.getElementById("pagamentos-chart"); | |
if (pagamentosChartElement) { | |
const pagamentosChart = echarts.init(pagamentosChartElement); | |
const pagamentosOption = { | |
animation: false, | |
tooltip: { | |
trigger: "item", | |
}, | |
legend: { | |
top: "5%", | |
left: "center", | |
}, | |
series: [ | |
{ | |
name: "Métodos de Pagamento", | |
type: "pie", | |
radius: ["40%", "70%"], | |
avoidLabelOverlap: false, | |
itemStyle: { | |
borderRadius: 10, | |
borderColor: "#fff", | |
borderWidth: 2, | |
}, | |
label: { | |
show: false, | |
position: "center", | |
}, | |
emphasis: { | |
label: { | |
show: true, | |
fontSize: 16, | |
fontWeight: "bold", | |
}, | |
}, | |
labelLine: { | |
show: false, | |
}, | |
data: [ | |
{ | |
value: 1048, | |
name: "Cartão de Crédito", | |
itemStyle: { color: "#8b5cf6" }, | |
}, | |
{ value: 735, name: "Pix", itemStyle: { color: "#22c55e" } }, | |
{ value: 580, name: "Boleto", itemStyle: { color: "#f59e0b" } }, | |
{ | |
value: 300, | |
name: "Transferência", | |
itemStyle: { color: "#3b82f6" }, | |
}, | |
], | |
}, | |
], | |
}; | |
pagamentosChart.setOption(pagamentosOption); | |
const handleResize = () => { | |
pagamentosChart.resize(); | |
}; | |
window.addEventListener("resize", handleResize); | |
return () => { | |
window.removeEventListener("resize", handleResize); | |
pagamentosChart.dispose(); | |
}; | |
} | |
// Reativação chart | |
const reativacaoChartElement = document.getElementById("reativacao-chart"); | |
if (reativacaoChartElement) { | |
const reativacaoChart = echarts.init(reativacaoChartElement); | |
const reativacaoOption = { | |
animation: false, | |
tooltip: { | |
trigger: "axis", | |
axisPointer: { | |
type: "shadow", | |
}, | |
}, | |
legend: {}, | |
grid: { | |
left: "3%", | |
right: "4%", | |
bottom: "3%", | |
containLabel: true, | |
}, | |
xAxis: { | |
type: "value", | |
boundaryGap: [0, 0.01], | |
}, | |
yAxis: { | |
type: "category", | |
data: [ | |
"Últimos 30 dias", | |
"Últimos 60 dias", | |
"Últimos 90 dias", | |
"Últimos 180 dias", | |
], | |
}, | |
series: [ | |
{ | |
name: "Clientes Reativados", | |
type: "bar", | |
data: [18, 32, 45, 62], | |
color: "#8b5cf6", | |
}, | |
{ | |
name: "Meta", | |
type: "bar", | |
data: [25, 40, 55, 70], | |
color: "#f59e0b", | |
}, | |
], | |
}; | |
reativacaoChart.setOption(reativacaoOption); | |
const handleResize = () => { | |
reativacaoChart.resize(); | |
}; | |
window.addEventListener("resize", handleResize); | |
return () => { | |
window.removeEventListener("resize", handleResize); | |
reativacaoChart.dispose(); | |
}; | |
} | |
}, [activeTab]); | |
const clientesData = [ | |
{ | |
id: 1, | |
nome: "Ana Silva", | |
email: "[email protected]", | |
telefone: "(11) 98765-4321", | |
ultimaCompra: "15/04/2025", | |
status: "Ativo", | |
}, | |
{ | |
id: 2, | |
nome: "Carlos Oliveira", | |
email: "[email protected]", | |
telefone: "(21) 91234-5678", | |
ultimaCompra: "10/04/2025", | |
status: "Ativo", | |
}, | |
{ | |
id: 3, | |
nome: "Mariana Santos", | |
email: "[email protected]", | |
telefone: "(31) 99876-5432", | |
ultimaCompra: "05/03/2025", | |
status: "Inativo", | |
}, | |
{ | |
id: 4, | |
nome: "Pedro Costa", | |
email: "[email protected]", | |
telefone: "(41) 98765-1234", | |
ultimaCompra: "20/02/2025", | |
status: "Inativo", | |
}, | |
{ | |
id: 5, | |
nome: "Juliana Lima", | |
email: "[email protected]", | |
telefone: "(51) 97654-3210", | |
ultimaCompra: "25/04/2025", | |
status: "Ativo", | |
}, | |
{ | |
id: 6, | |
nome: "Roberto Alves", | |
email: "[email protected]", | |
telefone: "(61) 96543-2109", | |
ultimaCompra: "18/04/2025", | |
status: "Ativo", | |
}, | |
]; | |
const vendasData = [ | |
{ | |
id: 1, | |
cliente: "Ana Silva", | |
produto: "Notebook Pro X", | |
valor: "R$ 3.599,90", | |
data: "15/04/2025", | |
status: "Concluída", | |
}, | |
{ | |
id: 2, | |
nome: "Carlos Oliveira", | |
produto: "Smartphone Galaxy S30", | |
valor: "R$ 2.899,90", | |
data: "10/04/2025", | |
status: "Concluída", | |
}, | |
{ | |
id: 3, | |
nome: "Mariana Santos", | |
produto: "Fone de Ouvido Bluetooth", | |
valor: "R$ 299,90", | |
data: "05/03/2025", | |
status: "Concluída", | |
}, | |
{ | |
id: 4, | |
nome: "Pedro Costa", | |
produto: 'Monitor 27" UltraWide', | |
valor: "R$ 1.599,90", | |
data: "20/02/2025", | |
status: "Cancelada", | |
}, | |
{ | |
id: 5, | |
nome: "Juliana Lima", | |
produto: "Teclado Mecânico RGB", | |
valor: "R$ 399,90", | |
data: "25/04/2025", | |
status: "Em processamento", | |
}, | |
]; | |
const pagamentosData = [ | |
{ | |
id: 1, | |
cliente: "Ana Silva", | |
valor: "R$ 3.599,90", | |
data: "15/04/2025", | |
metodo: "Cartão de Crédito", | |
status: "Aprovado", | |
}, | |
{ | |
id: 2, | |
cliente: "Carlos Oliveira", | |
valor: "R$ 2.899,90", | |
data: "10/04/2025", | |
metodo: "Pix", | |
status: "Aprovado", | |
}, | |
{ | |
id: 3, | |
cliente: "Mariana Santos", | |
valor: "R$ 299,90", | |
data: "05/03/2025", | |
metodo: "Boleto", | |
status: "Aprovado", | |
}, | |
{ | |
id: 4, | |
cliente: "Pedro Costa", | |
valor: "R$ 1.599,90", | |
data: "20/02/2025", | |
metodo: "Transferência", | |
status: "Cancelado", | |
}, | |
{ | |
id: 5, | |
cliente: "Juliana Lima", | |
valor: "R$ 399,90", | |
data: "25/04/2025", | |
metodo: "Cartão de Crédito", | |
status: "Pendente", | |
}, | |
]; | |
const reativacaoData = [ | |
{ | |
id: 1, | |
cliente: "Mariana Santos", | |
ultimaCompra: "05/03/2025", | |
diasInativo: 55, | |
potencial: "Alto", | |
campanha: "Desconto 20%", | |
}, | |
{ | |
id: 2, | |
cliente: "Pedro Costa", | |
ultimaCompra: "20/02/2025", | |
diasInativo: 68, | |
potencial: "Médio", | |
campanha: "Frete Grátis", | |
}, | |
{ | |
id: 3, | |
cliente: "Fernanda Dias", | |
ultimaCompra: "10/01/2025", | |
diasInativo: 109, | |
potencial: "Baixo", | |
campanha: "Cupom Especial", | |
}, | |
{ | |
id: 4, | |
cliente: "Ricardo Souza", | |
ultimaCompra: "15/12/2024", | |
diasInativo: 135, | |
potencial: "Alto", | |
campanha: "Oferta Exclusiva", | |
}, | |
]; | |
return ( | |
<div className="min-h-screen bg-slate-50 font-sans"> | |
{/* Header */} | |
<header className="bg-white shadow-sm py-4 px-4 md:px-6"> | |
<div className="max-w-7xl mx-auto flex flex-col md:flex-row justify-between items-center"> | |
<div className="flex items-center mb-4 md:mb-0"> | |
<div className="w-10 h-10 rounded-full bg-purple-600 flex items-center justify-center text-white font-bold mr-3"> | |
R | |
</div> | |
<h1 className="text-2xl font-bold text-purple-600">Reativou</h1> | |
</div> | |
<div className="flex items-center space-x-4"> | |
<div className="relative"> | |
<Input | |
type="text" | |
placeholder="Pesquisar..." | |
className="w-full md:w-64 pl-10 border-slate-200 focus:border-purple-500 focus:ring-purple-500 text-sm" | |
/> | |
<i className="fas fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-slate-400"></i> | |
</div> | |
<Button | |
variant="outline" | |
size="sm" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-bell mr-2"></i> | |
Notificações | |
</Button> | |
<Avatar className="cursor-pointer"> | |
<AvatarImage | |
src="https://readdy.ai/api/search-image?query=professional%20portrait%20photo%20of%20a%20Brazilian%20person%20with%20neutral%20expression%2C%20high%20quality%2C%20studio%20lighting%2C%20professional%20headshot%2C%20business%20attire&width=100&height=100&seq=avatar1&orientation=squarish" | |
alt="Usuário" | |
/> | |
<AvatarFallback>US</AvatarFallback> | |
</Avatar> | |
</div> | |
</div> | |
</header> | |
{/* Main Content */} | |
<main className="max-w-7xl mx-auto p-4 md:p-6"> | |
{/* Dashboard Header */} | |
<div className="mb-6"> | |
<h2 className="text-2xl font-bold text-slate-800 mb-2">Dashboard</h2> | |
<p className="text-slate-600"> | |
Bem-vindo ao seu painel de controle, 29 de abril de 2025 | |
</p> | |
</div> | |
{/* Quick Stats */} | |
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6"> | |
<Card> | |
<CardContent className="p-6"> | |
<div className="flex justify-between items-start"> | |
<div> | |
<p className="text-sm font-medium text-slate-500 mb-1"> | |
Total de Clientes | |
</p> | |
<h3 className="text-2xl font-bold text-slate-800">156</h3> | |
<p className="text-sm text-green-600 mt-1"> | |
<i className="fas fa-arrow-up mr-1"></i> | |
12% este mês | |
</p> | |
</div> | |
<div className="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center"> | |
<i className="fas fa-users text-purple-600"></i> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
<Card> | |
<CardContent className="p-6"> | |
<div className="flex justify-between items-start"> | |
<div> | |
<p className="text-sm font-medium text-slate-500 mb-1"> | |
Vendas do Mês | |
</p> | |
<h3 className="text-2xl font-bold text-slate-800"> | |
R$ 24.590 | |
</h3> | |
<p className="text-sm text-green-600 mt-1"> | |
<i className="fas fa-arrow-up mr-1"></i> | |
8% vs. último mês | |
</p> | |
</div> | |
<div className="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center"> | |
<i className="fas fa-shopping-cart text-green-600"></i> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
<Card> | |
<CardContent className="p-6"> | |
<div className="flex justify-between items-start"> | |
<div> | |
<p className="text-sm font-medium text-slate-500 mb-1"> | |
Taxa de Conversão | |
</p> | |
<h3 className="text-2xl font-bold text-slate-800">18,5%</h3> | |
<p className="text-sm text-red-600 mt-1"> | |
<i className="fas fa-arrow-down mr-1"></i> | |
2% vs. último mês | |
</p> | |
</div> | |
<div className="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center"> | |
<i className="fas fa-chart-line text-blue-600"></i> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
<Card> | |
<CardContent className="p-6"> | |
<div className="flex justify-between items-start"> | |
<div> | |
<p className="text-sm font-medium text-slate-500 mb-1"> | |
Clientes Reativados | |
</p> | |
<h3 className="text-2xl font-bold text-slate-800">32</h3> | |
<p className="text-sm text-green-600 mt-1"> | |
<i className="fas fa-arrow-up mr-1"></i> | |
15% este mês | |
</p> | |
</div> | |
<div className="w-10 h-10 rounded-full bg-amber-100 flex items-center justify-center"> | |
<i className="fas fa-sync-alt text-amber-600"></i> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
</div> | |
{/* Main Tabs */} | |
<Tabs | |
defaultValue="clientes" | |
className="w-full" | |
onValueChange={setActiveTab} | |
> | |
<TabsList className="grid grid-cols-4 mb-6"> | |
<TabsTrigger | |
value="clientes" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-user-friends mr-2"></i> | |
Clientes | |
</TabsTrigger> | |
<TabsTrigger | |
value="vendas" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-shopping-bag mr-2"></i> | |
Vendas | |
</TabsTrigger> | |
<TabsTrigger | |
value="pagamentos" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-credit-card mr-2"></i> | |
Pagamentos | |
</TabsTrigger> | |
<TabsTrigger | |
value="reativacao" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-sync mr-2"></i> | |
Reativação | |
</TabsTrigger> | |
</TabsList> | |
{/* Clientes Tab Content */} | |
<TabsContent value="clientes" className="mt-0"> | |
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
<Card className="lg:col-span-2"> | |
<CardHeader className="pb-2"> | |
<div className="flex justify-between items-center"> | |
<CardTitle>Clientes Recentes</CardTitle> | |
<Button | |
variant="outline" | |
size="sm" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-plus mr-2"></i> | |
Novo Cliente | |
</Button> | |
</div> | |
<CardDescription> | |
Lista dos últimos clientes cadastrados | |
</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div className="overflow-x-auto"> | |
<table className="w-full"> | |
<thead> | |
<tr className="border-b border-slate-200"> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Nome | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Última Compra | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Status | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Ações | |
</th> | |
</tr> | |
</thead> | |
<tbody> | |
{clientesData.map((cliente) => ( | |
<tr | |
key={cliente.id} | |
className="border-b border-slate-100 hover:bg-slate-50" | |
> | |
<td className="py-3 px-4"> | |
<div className="flex items-center"> | |
<Avatar className="mr-2 h-8 w-8"> | |
<AvatarFallback> | |
{cliente.nome | |
.split(" ") | |
.map((n) => n[0]) | |
.join("")} | |
</AvatarFallback> | |
</Avatar> | |
<span className="font-medium"> | |
{cliente.nome} | |
</span> | |
</div> | |
</td> | |
<td className="py-3 px-4 text-slate-600"> | |
{cliente.email} | |
</td> | |
<td className="py-3 px-4 text-slate-600"> | |
{cliente.ultimaCompra} | |
</td> | |
<td className="py-3 px-4"> | |
<Badge | |
variant={ | |
cliente.status === "Ativo" | |
? "default" | |
: "secondary" | |
} | |
className={`${cliente.status === "Ativo" ? "bg-green-100 text-green-800" : "bg-slate-100 text-slate-800"}`} | |
> | |
{cliente.status} | |
</Badge> | |
</td> | |
<td className="py-3 px-4"> | |
<div className="flex space-x-2"> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fas fa-eye text-slate-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fas fa-edit text-blue-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fas fa-trash text-red-600"></i> | |
</Button> | |
</div> | |
</td> | |
</tr> | |
))} | |
</tbody> | |
</table> | |
</div> | |
<div className="flex justify-between items-center mt-4"> | |
<p className="text-sm text-slate-600"> | |
Mostrando 1-6 de 156 clientes | |
</p> | |
<div className="flex space-x-2"> | |
<Button | |
variant="outline" | |
size="sm" | |
disabled | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-chevron-left mr-1"></i> | |
Anterior | |
</Button> | |
<Button | |
variant="outline" | |
size="sm" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
Próximo | |
<i className="fas fa-chevron-right ml-1"></i> | |
</Button> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
<div className="space-y-6"> | |
<Card> | |
<CardHeader className="pb-2"> | |
<CardTitle>Segmentação de Clientes</CardTitle> | |
<CardDescription>Distribuição por status</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div className="space-y-4"> | |
<div className="flex justify-between items-center"> | |
<div className="flex items-center"> | |
<div className="w-3 h-3 rounded-full bg-green-500 mr-2"></div> | |
<span className="text-sm font-medium">Ativos</span> | |
</div> | |
<div className="flex items-center"> | |
<span className="font-medium">98</span> | |
<span className="text-sm text-slate-500 ml-1"> | |
(63%) | |
</span> | |
</div> | |
</div> | |
<div className="w-full bg-slate-100 rounded-full h-2"> | |
<div | |
className="bg-green-500 h-2 rounded-full" | |
style={{ width: "63%" }} | |
></div> | |
</div> | |
<div className="flex justify-between items-center"> | |
<div className="flex items-center"> | |
<div className="w-3 h-3 rounded-full bg-amber-500 mr-2"></div> | |
<span className="text-sm font-medium"> | |
Inativos (30-60 dias) | |
</span> | |
</div> | |
<div className="flex items-center"> | |
<span className="font-medium">32</span> | |
<span className="text-sm text-slate-500 ml-1"> | |
(20%) | |
</span> | |
</div> | |
</div> | |
<div className="w-full bg-slate-100 rounded-full h-2"> | |
<div | |
className="bg-amber-500 h-2 rounded-full" | |
style={{ width: "20%" }} | |
></div> | |
</div> | |
<div className="flex justify-between items-center"> | |
<div className="flex items-center"> | |
<div className="w-3 h-3 rounded-full bg-red-500 mr-2"></div> | |
<span className="text-sm font-medium"> | |
Inativos (+60 dias) | |
</span> | |
</div> | |
<div className="flex items-center"> | |
<span className="font-medium">26</span> | |
<span className="text-sm text-slate-500 ml-1"> | |
(17%) | |
</span> | |
</div> | |
</div> | |
<div className="w-full bg-slate-100 rounded-full h-2"> | |
<div | |
className="bg-red-500 h-2 rounded-full" | |
style={{ width: "17%" }} | |
></div> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
<Card> | |
<CardHeader className="pb-2"> | |
<CardTitle>Ações Rápidas</CardTitle> | |
<CardDescription>Gerenciamento de clientes</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div className="space-y-3"> | |
<Dialog | |
open={addClientOpen} | |
onOpenChange={setAddClientOpen} | |
> | |
<DialogTrigger asChild> | |
<Button className="w-full justify-start !rounded-button whitespace-nowrap cursor-pointer"> | |
<i className="fas fa-plus mr-2"></i> | |
Adicionar Cliente | |
</Button> | |
</DialogTrigger> | |
<DialogContent className="sm:max-w-[425px]"> | |
<DialogHeader> | |
<DialogTitle>Adicionar Novo Cliente</DialogTitle> | |
<DialogDescription> | |
Preencha os dados do novo cliente. Todos os campos | |
são obrigatórios. | |
</DialogDescription> | |
</DialogHeader> | |
<form | |
onSubmit={handleAddClient} | |
className="space-y-4 mt-4" | |
> | |
<div className="space-y-2"> | |
<Label htmlFor="name">Nome</Label> | |
<Input | |
id="name" | |
value={newClient.name} | |
onChange={(e) => | |
setNewClient({ | |
...newClient, | |
name: e.target.value, | |
}) | |
} | |
placeholder="Nome completo" | |
className="!rounded-button" | |
required | |
/> | |
</div> | |
<div className="space-y-2"> | |
<Label htmlFor="email">E-mail</Label> | |
<Input | |
id="email" | |
type="email" | |
value={newClient.email} | |
onChange={(e) => | |
setNewClient({ | |
...newClient, | |
email: e.target.value, | |
}) | |
} | |
placeholder="[email protected]" | |
className="!rounded-button" | |
required | |
/> | |
</div> | |
<div className="space-y-2"> | |
<Label htmlFor="phone">Telefone</Label> | |
<Input | |
id="phone" | |
value={newClient.phone} | |
onChange={(e) => | |
setNewClient({ | |
...newClient, | |
phone: e.target.value, | |
}) | |
} | |
placeholder="(00) 00000-0000" | |
className="!rounded-button" | |
required | |
/> | |
</div> | |
<div className="space-y-2"> | |
<Label htmlFor="status">Status</Label> | |
<Select | |
value={newClient.status} | |
onValueChange={(value) => | |
setNewClient({ ...newClient, status: value }) | |
} | |
> | |
<SelectTrigger className="w-full !rounded-button"> | |
<SelectValue placeholder="Selecione o status" /> | |
</SelectTrigger> | |
<SelectContent> | |
<SelectItem value="Ativo">Ativo</SelectItem> | |
<SelectItem value="Inativo"> | |
Inativo | |
</SelectItem> | |
</SelectContent> | |
</Select> | |
</div> | |
<div className="flex justify-end space-x-2 mt-6"> | |
<Button | |
type="button" | |
variant="outline" | |
onClick={() => setAddClientOpen(false)} | |
className="!rounded-button whitespace-nowrap" | |
> | |
Cancelar | |
</Button> | |
<Button | |
type="submit" | |
className="!rounded-button whitespace-nowrap" | |
> | |
Salvar Cliente | |
</Button> | |
</div> | |
</form> | |
</DialogContent> | |
</Dialog> | |
<Dialog | |
open={importClientOpen} | |
onOpenChange={setImportClientOpen} | |
> | |
<DialogTrigger asChild> | |
<Button | |
variant="outline" | |
className="w-full justify-start !rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-file-import mr-2"></i> | |
Importar Clientes | |
</Button> | |
</DialogTrigger> | |
<DialogContent className="sm:max-w-[425px]"> | |
<DialogHeader> | |
<DialogTitle>Importar Clientes</DialogTitle> | |
<DialogDescription> | |
Faça upload de um arquivo CSV ou Excel com a lista | |
de clientes. | |
</DialogDescription> | |
</DialogHeader> | |
<form | |
onSubmit={handleImportClients} | |
className="space-y-4 mt-4" | |
> | |
<div className="space-y-4"> | |
<div className="border-2 border-dashed border-slate-200 rounded-lg p-6 text-center"> | |
<input | |
type="file" | |
id="file-upload" | |
className="hidden" | |
accept=".csv,.xlsx,.xls" | |
onChange={handleFileChange} | |
/> | |
<label | |
htmlFor="file-upload" | |
className="cursor-pointer flex flex-col items-center space-y-2" | |
> | |
<div className="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center"> | |
<i className="fas fa-cloud-upload-alt text-purple-600 text-xl"></i> | |
</div> | |
<div className="text-sm text-slate-600"> | |
{selectedFile ? ( | |
<span className="text-purple-600 font-medium"> | |
{selectedFile.name} | |
</span> | |
) : ( | |
<> | |
<span className="text-purple-600 font-medium"> | |
Clique para fazer upload | |
</span> | |
<span> ou arraste e solte</span> | |
</> | |
)} | |
</div> | |
<div className="text-xs text-slate-500"> | |
CSV, Excel até 10MB | |
</div> | |
</label> | |
</div> | |
<div className="bg-purple-50 rounded-lg p-4 text-sm text-purple-800"> | |
<h4 className="font-medium mb-2"> | |
Formato do arquivo: | |
</h4> | |
<ul className="list-disc list-inside space-y-1 text-purple-700"> | |
<li>Nome (obrigatório)</li> | |
<li>E-mail (obrigatório)</li> | |
<li>Telefone (obrigatório)</li> | |
<li>Status (opcional, padrão: Ativo)</li> | |
</ul> | |
</div> | |
</div> | |
<div className="flex justify-end space-x-2 mt-6"> | |
<Button | |
type="button" | |
variant="outline" | |
onClick={() => setImportClientOpen(false)} | |
className="!rounded-button whitespace-nowrap" | |
> | |
Cancelar | |
</Button> | |
<Button | |
type="submit" | |
disabled={!selectedFile} | |
className="!rounded-button whitespace-nowrap" | |
> | |
Importar Clientes | |
</Button> | |
</div> | |
</form> | |
</DialogContent> | |
</Dialog> | |
<Dialog> | |
<DialogTrigger asChild> | |
<Button | |
variant="outline" | |
className="w-full justify-start !rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-tag mr-2"></i> | |
Gerenciar Tags | |
</Button> | |
</DialogTrigger> | |
<DialogContent className="sm:max-w-[425px]"> | |
<DialogHeader> | |
<DialogTitle>Gerenciar Tags</DialogTitle> | |
<DialogDescription> | |
Adicione, edite ou remova tags para organizar seus | |
clientes. | |
</DialogDescription> | |
</DialogHeader> | |
<div className="space-y-4 mt-4"> | |
<div className="flex space-x-2"> | |
<Input | |
placeholder="Nova tag..." | |
className="!rounded-button" | |
/> | |
<Button className="!rounded-button whitespace-nowrap"> | |
<i className="fas fa-plus mr-2"></i> | |
Adicionar | |
</Button> | |
</div> | |
<div className="space-y-2"> | |
<div className="flex items-center justify-between p-2 bg-slate-50 rounded-lg"> | |
<span className="font-medium">VIP</span> | |
<div className="flex space-x-2"> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button" | |
> | |
<i className="fas fa-edit text-blue-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button" | |
> | |
<i className="fas fa-trash text-red-600"></i> | |
</Button> | |
</div> | |
</div> | |
<div className="flex items-center justify-between p-2 bg-slate-50 rounded-lg"> | |
<span className="font-medium"> | |
Cliente Recorrente | |
</span> | |
<div className="flex space-x-2"> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button" | |
> | |
<i className="fas fa-edit text-blue-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button" | |
> | |
<i className="fas fa-trash text-red-600"></i> | |
</Button> | |
</div> | |
</div> | |
<div className="flex items-center justify-between p-2 bg-slate-50 rounded-lg"> | |
<span className="font-medium"> | |
Alto Potencial | |
</span> | |
<div className="flex space-x-2"> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button" | |
> | |
<i className="fas fa-edit text-blue-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button" | |
> | |
<i className="fas fa-trash text-red-600"></i> | |
</Button> | |
</div> | |
</div> | |
</div> | |
</div> | |
</DialogContent> | |
</Dialog> | |
<Dialog> | |
<DialogTrigger asChild> | |
<Button | |
variant="outline" | |
className="w-full justify-start !rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-filter mr-2"></i> | |
Filtros Avançados | |
</Button> | |
</DialogTrigger> | |
<DialogContent className="sm:max-w-[425px]"> | |
<DialogHeader> | |
<DialogTitle>Filtros Avançados</DialogTitle> | |
<DialogDescription> | |
Refine sua busca de clientes usando múltiplos | |
critérios. | |
</DialogDescription> | |
</DialogHeader> | |
<form className="space-y-4 mt-4"> | |
<div className="space-y-2"> | |
<Label>Status do Cliente</Label> | |
<div className="space-y-2"> | |
<div className="flex items-center space-x-2"> | |
<input | |
type="checkbox" | |
id="status-ativo" | |
className="rounded border-slate-300" | |
/> | |
<label htmlFor="status-ativo">Ativo</label> | |
</div> | |
<div className="flex items-center space-x-2"> | |
<input | |
type="checkbox" | |
id="status-inativo-30-60" | |
className="rounded border-slate-300" | |
/> | |
<label htmlFor="status-inativo-30-60"> | |
Inativo (30-60 dias) | |
</label> | |
</div> | |
<div className="flex items-center space-x-2"> | |
<input | |
type="checkbox" | |
id="status-inativo-60" | |
className="rounded border-slate-300" | |
/> | |
<label htmlFor="status-inativo-60"> | |
Inativo (+60 dias) | |
</label> | |
</div> | |
</div> | |
</div> | |
<div className="space-y-2"> | |
<Label>Data da Última Compra</Label> | |
<div className="grid grid-cols-2 gap-2"> | |
<div className="space-y-1"> | |
<Label className="text-sm text-slate-500"> | |
De | |
</Label> | |
<Input | |
type="date" | |
className="!rounded-button" | |
/> | |
</div> | |
<div className="space-y-1"> | |
<Label className="text-sm text-slate-500"> | |
Até | |
</Label> | |
<Input | |
type="date" | |
className="!rounded-button" | |
/> | |
</div> | |
</div> | |
</div> | |
<div className="space-y-2"> | |
<Label>Buscar por Nome ou E-mail</Label> | |
<Input | |
type="text" | |
placeholder="Digite nome ou e-mail..." | |
className="!rounded-button" | |
/> | |
</div> | |
<div className="flex justify-end space-x-2 mt-6"> | |
<Button | |
variant="outline" | |
className="!rounded-button whitespace-nowrap" | |
> | |
Limpar Filtros | |
</Button> | |
<Button | |
type="submit" | |
className="!rounded-button whitespace-nowrap" | |
> | |
<i className="fas fa-check mr-2"></i> | |
Aplicar Filtros | |
</Button> | |
</div> | |
</form> | |
</DialogContent> | |
</Dialog> | |
<Dialog> | |
<DialogTrigger asChild> | |
<Button | |
variant="outline" | |
className="w-full justify-start !rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-file-export mr-2"></i> | |
Exportar Relatório | |
</Button> | |
</DialogTrigger> | |
<DialogContent className="sm:max-w-[425px]"> | |
<DialogHeader> | |
<DialogTitle>Exportar Relatório</DialogTitle> | |
<DialogDescription> | |
Selecione as opções para exportar os dados dos | |
clientes. | |
</DialogDescription> | |
</DialogHeader> | |
<form className="space-y-4 mt-4"> | |
<div className="space-y-2"> | |
<Label>Período</Label> | |
<Select defaultValue="30"> | |
<SelectTrigger className="w-full !rounded-button"> | |
<SelectValue placeholder="Selecione o período" /> | |
</SelectTrigger> | |
<SelectContent> | |
<SelectItem value="30"> | |
Últimos 30 dias | |
</SelectItem> | |
<SelectItem value="90"> | |
Últimos 90 dias | |
</SelectItem> | |
<SelectItem value="custom"> | |
Período personalizado | |
</SelectItem> | |
</SelectContent> | |
</Select> | |
</div> | |
<div className="space-y-2"> | |
<Label>Tipo de Dados</Label> | |
<div className="space-y-2"> | |
<div className="flex items-center space-x-2"> | |
<input | |
type="radio" | |
id="all-fields" | |
name="data-type" | |
className="rounded-full border-slate-300" | |
defaultChecked | |
/> | |
<label htmlFor="all-fields"> | |
Todos os campos | |
</label> | |
</div> | |
<div className="flex items-center space-x-2"> | |
<input | |
type="radio" | |
id="main-fields" | |
name="data-type" | |
className="rounded-full border-slate-300" | |
/> | |
<label htmlFor="main-fields"> | |
Apenas campos principais | |
</label> | |
</div> | |
</div> | |
</div> | |
<div className="space-y-2"> | |
<Label>Formato do Arquivo</Label> | |
<div className="grid grid-cols-2 gap-4"> | |
<Button | |
type="button" | |
variant="outline" | |
className="!rounded-button whitespace-nowrap" | |
> | |
<i className="fas fa-file-csv mr-2"></i> | |
CSV | |
</Button> | |
<Button | |
type="button" | |
variant="outline" | |
className="!rounded-button whitespace-nowrap" | |
> | |
<i className="fas fa-file-excel mr-2"></i> | |
Excel | |
</Button> | |
</div> | |
</div> | |
<div className="bg-purple-50 rounded-lg p-4 text-sm text-purple-800"> | |
<h4 className="font-medium mb-2"> | |
Campos incluídos: | |
</h4> | |
<ul className="list-disc list-inside space-y-1 text-purple-700"> | |
<li>Nome do cliente</li> | |
<li>E-mail</li> | |
<li>Telefone</li> | |
<li>Status</li> | |
<li>Data da última compra</li> | |
<li>Total em compras</li> | |
</ul> | |
</div> | |
<div className="flex justify-end space-x-2 mt-6"> | |
<Button | |
variant="outline" | |
className="!rounded-button whitespace-nowrap" | |
> | |
Cancelar | |
</Button> | |
<Button | |
type="submit" | |
className="!rounded-button whitespace-nowrap" | |
> | |
<i className="fas fa-download mr-2"></i> | |
Exportar Relatório | |
</Button> | |
</div> | |
</form> | |
</DialogContent> | |
</Dialog> | |
</div> | |
</CardContent> | |
</Card> | |
</div> | |
</div> | |
</TabsContent> | |
{/* Vendas Tab Content */} | |
<TabsContent value="vendas" className="mt-0"> | |
<div className="mb-6"> | |
<Dialog> | |
<DialogTrigger asChild> | |
<Button className="!rounded-button whitespace-nowrap cursor-pointer"> | |
<i className="fas fa-plus mr-2"></i> | |
Nova Venda | |
</Button> | |
</DialogTrigger> | |
<DialogContent className="sm:max-w-[600px]"> | |
<DialogHeader> | |
<DialogTitle>Nova Venda</DialogTitle> | |
<DialogDescription> | |
Registre uma nova venda preenchendo os dados abaixo. | |
</DialogDescription> | |
</DialogHeader> | |
<form className="space-y-4 mt-4"> | |
<div className="space-y-2"> | |
<Label htmlFor="cliente">Cliente</Label> | |
<Select> | |
<SelectTrigger className="w-full !rounded-button"> | |
<SelectValue placeholder="Selecione o cliente" /> | |
</SelectTrigger> | |
<SelectContent> | |
{clientesData.map((cliente) => ( | |
<SelectItem | |
key={cliente.id} | |
value={cliente.id.toString()} | |
> | |
{cliente.nome} | |
</SelectItem> | |
))} | |
</SelectContent> | |
</Select> | |
</div> | |
<div className="space-y-2"> | |
<Label>Produtos</Label> | |
<div className="space-y-3"> | |
<div className="flex gap-3"> | |
<Select className="flex-1"> | |
<SelectTrigger className="!rounded-button"> | |
<SelectValue placeholder="Selecione o produto" /> | |
</SelectTrigger> | |
<SelectContent> | |
<SelectItem value="1">Notebook Pro X</SelectItem> | |
<SelectItem value="2"> | |
Smartphone Galaxy S30 | |
</SelectItem> | |
<SelectItem value="3"> | |
Fone de Ouvido Bluetooth | |
</SelectItem> | |
<SelectItem value="4"> | |
Monitor 27" UltraWide | |
</SelectItem> | |
<SelectItem value="5"> | |
Teclado Mecânico RGB | |
</SelectItem> | |
</SelectContent> | |
</Select> | |
<Input | |
type="number" | |
placeholder="Qtd" | |
min="1" | |
className="w-20 !rounded-button" | |
/> | |
<Input | |
type="number" | |
placeholder="Preço" | |
className="w-32 !rounded-button" | |
/> | |
<Button | |
variant="outline" | |
size="icon" | |
className="!rounded-button" | |
> | |
<i className="fas fa-trash text-red-600"></i> | |
</Button> | |
</div> | |
</div> | |
<Button | |
type="button" | |
variant="outline" | |
className="w-full mt-2 !rounded-button whitespace-nowrap" | |
> | |
<i className="fas fa-plus mr-2"></i> | |
Adicionar Produto | |
</Button> | |
</div> | |
<div className="grid grid-cols-2 gap-4"> | |
<div className="space-y-2"> | |
<Label htmlFor="payment">Método de Pagamento</Label> | |
<Select> | |
<SelectTrigger className="w-full !rounded-button"> | |
<SelectValue placeholder="Selecione o método" /> | |
</SelectTrigger> | |
<SelectContent> | |
<SelectItem value="credit"> | |
Cartão de Crédito | |
</SelectItem> | |
<SelectItem value="pix">Pix</SelectItem> | |
<SelectItem value="boleto">Boleto</SelectItem> | |
<SelectItem value="transfer"> | |
Transferência | |
</SelectItem> | |
</SelectContent> | |
</Select> | |
</div> | |
<div className="space-y-2"> | |
<Label htmlFor="status">Status</Label> | |
<Select> | |
<SelectTrigger className="w-full !rounded-button"> | |
<SelectValue placeholder="Selecione o status" /> | |
</SelectTrigger> | |
<SelectContent> | |
<SelectItem value="concluida">Concluída</SelectItem> | |
<SelectItem value="processamento"> | |
Em processamento | |
</SelectItem> | |
<SelectItem value="cancelada">Cancelada</SelectItem> | |
</SelectContent> | |
</Select> | |
</div> | |
</div> | |
<div className="space-y-2"> | |
<Label htmlFor="observacoes">Observações</Label> | |
<Input | |
id="observacoes" | |
placeholder="Adicione observações sobre a venda" | |
className="!rounded-button" | |
/> | |
</div> | |
<div className="bg-slate-50 p-4 rounded-lg"> | |
<div className="flex justify-between items-center text-sm"> | |
<span className="text-slate-600">Subtotal:</span> | |
<span className="font-medium">R$ 0,00</span> | |
</div> | |
<div className="flex justify-between items-center text-sm mt-2"> | |
<span className="text-slate-600">Desconto:</span> | |
<span className="font-medium">R$ 0,00</span> | |
</div> | |
<div className="flex justify-between items-center font-medium mt-2 pt-2 border-t border-slate-200"> | |
<span>Total:</span> | |
<span className="text-lg">R$ 0,00</span> | |
</div> | |
</div> | |
<div className="flex justify-end space-x-2 mt-6"> | |
<Button | |
variant="outline" | |
className="!rounded-button whitespace-nowrap" | |
> | |
Cancelar | |
</Button> | |
<Button | |
type="submit" | |
className="!rounded-button whitespace-nowrap" | |
> | |
<i className="fas fa-check mr-2"></i> | |
Salvar Venda | |
</Button> | |
</div> | |
</form> | |
</DialogContent> | |
</Dialog> | |
</div> | |
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
<Card className="lg:col-span-2"> | |
<CardHeader className="pb-2"> | |
<div className="flex justify-between items-center"> | |
<CardTitle>Histórico de Vendas</CardTitle> | |
<Button | |
variant="outline" | |
size="sm" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-filter mr-2"></i> | |
Filtrar | |
</Button> | |
</div> | |
<CardDescription> | |
Últimas transações realizadas | |
</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div className="overflow-x-auto"> | |
<table className="w-full"> | |
<thead> | |
<tr className="border-b border-slate-200"> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Cliente | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Produto | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Valor | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Data | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Status | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Ações | |
</th> | |
</tr> | |
</thead> | |
<tbody> | |
{vendasData.map((venda) => ( | |
<tr | |
key={venda.id} | |
className="border-b border-slate-100 hover:bg-slate-50" | |
> | |
<td className="py-3 px-4 font-medium"> | |
{venda.cliente} | |
</td> | |
<td className="py-3 px-4 text-slate-600"> | |
{venda.produto} | |
</td> | |
<td className="py-3 px-4 font-medium"> | |
{venda.valor} | |
</td> | |
<td className="py-3 px-4 text-slate-600"> | |
{venda.data} | |
</td> | |
<td className="py-3 px-4"> | |
<Badge | |
variant="outline" | |
className={` | |
${ | |
venda.status === "Concluída" | |
? "bg-green-100 text-green-800 border-green-200" | |
: venda.status === "Em processamento" | |
? "bg-blue-100 text-blue-800 border-blue-200" | |
: "bg-red-100 text-red-800 border-red-200" | |
} | |
`} | |
> | |
{venda.status} | |
</Badge> | |
</td> | |
<td className="py-3 px-4"> | |
<div className="flex space-x-2"> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fas fa-eye text-slate-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fas fa-receipt text-purple-600"></i> | |
</Button> | |
</div> | |
</td> | |
</tr> | |
))} | |
</tbody> | |
</table> | |
</div> | |
<div className="flex justify-between items-center mt-4"> | |
<p className="text-sm text-slate-600"> | |
Mostrando 1-5 de 42 vendas | |
</p> | |
<div className="flex space-x-2"> | |
<Button | |
variant="outline" | |
size="sm" | |
disabled | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-chevron-left mr-1"></i> | |
Anterior | |
</Button> | |
<Button | |
variant="outline" | |
size="sm" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
Próximo | |
<i className="fas fa-chevron-right ml-1"></i> | |
</Button> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
<div className="space-y-6"> | |
<Card> | |
<CardHeader className="pb-2"> | |
<CardTitle>Desempenho de Vendas</CardTitle> | |
<CardDescription>Últimos 6 meses</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div | |
id="vendas-chart" | |
style={{ width: "100%", height: "300px" }} | |
></div> | |
</CardContent> | |
</Card> | |
<Card> | |
<CardHeader className="pb-2"> | |
<CardTitle>Produtos Mais Vendidos</CardTitle> | |
<CardDescription>Top 5 produtos do mês</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div className="space-y-4"> | |
<div className="flex justify-between items-center"> | |
<div className="flex items-center"> | |
<div className="w-10 h-10 rounded bg-purple-100 flex items-center justify-center mr-3"> | |
<i className="fas fa-laptop text-purple-600"></i> | |
</div> | |
<div> | |
<p className="font-medium">Notebook Pro X</p> | |
<p className="text-sm text-slate-500"> | |
32 unidades | |
</p> | |
</div> | |
</div> | |
<span className="font-medium">R$ 115.197</span> | |
</div> | |
<div className="flex justify-between items-center"> | |
<div className="flex items-center"> | |
<div className="w-10 h-10 rounded bg-blue-100 flex items-center justify-center mr-3"> | |
<i className="fas fa-mobile-alt text-blue-600"></i> | |
</div> | |
<div> | |
<p className="font-medium">Smartphone Galaxy S30</p> | |
<p className="text-sm text-slate-500"> | |
28 unidades | |
</p> | |
</div> | |
</div> | |
<span className="font-medium">R$ 81.197</span> | |
</div> | |
<div className="flex justify-between items-center"> | |
<div className="flex items-center"> | |
<div className="w-10 h-10 rounded bg-green-100 flex items-center justify-center mr-3"> | |
<i className="fas fa-headphones text-green-600"></i> | |
</div> | |
<div> | |
<p className="font-medium"> | |
Fone de Ouvido Bluetooth | |
</p> | |
<p className="text-sm text-slate-500"> | |
45 unidades | |
</p> | |
</div> | |
</div> | |
<span className="font-medium">R$ 13.496</span> | |
</div> | |
<div className="flex justify-between items-center"> | |
<div className="flex items-center"> | |
<div className="w-10 h-10 rounded bg-amber-100 flex items-center justify-center mr-3"> | |
<i className="fas fa-desktop text-amber-600"></i> | |
</div> | |
<div> | |
<p className="font-medium">Monitor 27" UltraWide</p> | |
<p className="text-sm text-slate-500"> | |
18 unidades | |
</p> | |
</div> | |
</div> | |
<span className="font-medium">R$ 28.798</span> | |
</div> | |
<div className="flex justify-between items-center"> | |
<div className="flex items-center"> | |
<div className="w-10 h-10 rounded bg-red-100 flex items-center justify-center mr-3"> | |
<i className="fas fa-keyboard text-red-600"></i> | |
</div> | |
<div> | |
<p className="font-medium">Teclado Mecânico RGB</p> | |
<p className="text-sm text-slate-500"> | |
22 unidades | |
</p> | |
</div> | |
</div> | |
<span className="font-medium">R$ 8.798</span> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
</div> | |
</div> | |
</TabsContent> | |
{/* Pagamentos Tab Content */} | |
<TabsContent value="pagamentos" className="mt-0"> | |
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
<Card className="lg:col-span-2"> | |
<CardHeader className="pb-2"> | |
<div className="flex justify-between items-center"> | |
<CardTitle>Histórico de Pagamentos</CardTitle> | |
<div className="flex space-x-2"> | |
<Select defaultValue="todos"> | |
<SelectTrigger className="w-[180px] !rounded-button"> | |
<SelectValue placeholder="Status" /> | |
</SelectTrigger> | |
<SelectContent> | |
<SelectItem value="todos">Todos os Status</SelectItem> | |
<SelectItem value="aprovado">Aprovados</SelectItem> | |
<SelectItem value="pendente">Pendentes</SelectItem> | |
<SelectItem value="cancelado">Cancelados</SelectItem> | |
</SelectContent> | |
</Select> | |
<Button | |
variant="outline" | |
size="sm" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-download mr-2"></i> | |
Exportar | |
</Button> | |
</div> | |
</div> | |
<CardDescription> | |
Transações financeiras recentes | |
</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div className="overflow-x-auto"> | |
<table className="w-full"> | |
<thead> | |
<tr className="border-b border-slate-200"> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Cliente | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Valor | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Data | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Método | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Status | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Ações | |
</th> | |
</tr> | |
</thead> | |
<tbody> | |
{pagamentosData.map((pagamento) => ( | |
<tr | |
key={pagamento.id} | |
className="border-b border-slate-100 hover:bg-slate-50" | |
> | |
<td className="py-3 px-4 font-medium"> | |
{pagamento.cliente} | |
</td> | |
<td className="py-3 px-4 font-medium"> | |
{pagamento.valor} | |
</td> | |
<td className="py-3 px-4 text-slate-600"> | |
{pagamento.data} | |
</td> | |
<td className="py-3 px-4"> | |
<div className="flex items-center"> | |
<i | |
className={` | |
fas | |
${ | |
pagamento.metodo === "Cartão de Crédito" | |
? "fa-credit-card text-purple-600" | |
: pagamento.metodo === "Pix" | |
? "fa-qrcode text-green-600" | |
: pagamento.metodo === "Boleto" | |
? "fa-file-invoice-dollar text-amber-600" | |
: "fa-university text-blue-600" | |
} | |
mr-2 | |
`} | |
></i> | |
{pagamento.metodo} | |
</div> | |
</td> | |
<td className="py-3 px-4"> | |
<Badge | |
variant="outline" | |
className={` | |
${ | |
pagamento.status === "Aprovado" | |
? "bg-green-100 text-green-800 border-green-200" | |
: pagamento.status === "Pendente" | |
? "bg-amber-100 text-amber-800 border-amber-200" | |
: "bg-red-100 text-red-800 border-red-200" | |
} | |
`} | |
> | |
{pagamento.status} | |
</Badge> | |
</td> | |
<td className="py-3 px-4"> | |
<div className="flex space-x-2"> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fas fa-eye text-slate-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fas fa-receipt text-purple-600"></i> | |
</Button> | |
</div> | |
</td> | |
</tr> | |
))} | |
</tbody> | |
</table> | |
</div> | |
<div className="flex justify-between items-center mt-4"> | |
<p className="text-sm text-slate-600"> | |
Mostrando 1-5 de 42 pagamentos | |
</p> | |
<div className="flex space-x-2"> | |
<Button | |
variant="outline" | |
size="sm" | |
disabled | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-chevron-left mr-1"></i> | |
Anterior | |
</Button> | |
<Button | |
variant="outline" | |
size="sm" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
Próximo | |
<i className="fas fa-chevron-right ml-1"></i> | |
</Button> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
<div className="space-y-6"> | |
<Card> | |
<CardHeader className="pb-2"> | |
<CardTitle>Métodos de Pagamento</CardTitle> | |
<CardDescription>Distribuição por método</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div | |
id="pagamentos-chart" | |
style={{ width: "100%", height: "300px" }} | |
></div> | |
</CardContent> | |
</Card> | |
<Card> | |
<CardHeader className="pb-2"> | |
<CardTitle>Resumo Financeiro</CardTitle> | |
<CardDescription>Visão geral do mês atual</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div className="space-y-4"> | |
<div className="flex justify-between items-center pb-3 border-b border-slate-100"> | |
<span className="text-slate-600">Total Recebido</span> | |
<span className="font-medium text-green-600"> | |
R$ 24.590,00 | |
</span> | |
</div> | |
<div className="flex justify-between items-center pb-3 border-b border-slate-100"> | |
<span className="text-slate-600">Pendente</span> | |
<span className="font-medium text-amber-600"> | |
R$ 3.250,00 | |
</span> | |
</div> | |
<div className="flex justify-between items-center pb-3 border-b border-slate-100"> | |
<span className="text-slate-600">Cancelado</span> | |
<span className="font-medium text-red-600"> | |
R$ 1.599,90 | |
</span> | |
</div> | |
<div className="flex justify-between items-center pb-3 border-b border-slate-100"> | |
<span className="text-slate-600">Taxa Média</span> | |
<span className="font-medium">3.2%</span> | |
</div> | |
<div className="flex justify-between items-center"> | |
<span className="text-slate-600">Ticket Médio</span> | |
<span className="font-medium">R$ 585,48</span> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
</div> | |
</div> | |
</TabsContent> | |
{/* Reativação Tab Content */} | |
<TabsContent value="reativacao" className="mt-0"> | |
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
<Card className="lg:col-span-2"> | |
<CardHeader className="pb-2"> | |
<div className="flex justify-between items-center"> | |
<CardTitle>Clientes para Reativação</CardTitle> | |
<Button | |
variant="outline" | |
size="sm" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-paper-plane mr-2"></i> | |
Campanha em Massa | |
</Button> | |
</div> | |
<CardDescription> | |
Clientes inativos com potencial de reativação | |
</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div className="overflow-x-auto"> | |
<table className="w-full"> | |
<thead> | |
<tr className="border-b border-slate-200"> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Cliente | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Última Compra | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Dias Inativo | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Potencial | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Campanha Sugerida | |
</th> | |
<th className="text-left py-3 px-4 font-medium text-slate-600"> | |
Ações | |
</th> | |
</tr> | |
</thead> | |
<tbody> | |
{reativacaoData.map((cliente) => ( | |
<tr | |
key={cliente.id} | |
className="border-b border-slate-100 hover:bg-slate-50" | |
> | |
<td className="py-3 px-4 font-medium"> | |
{cliente.cliente} | |
</td> | |
<td className="py-3 px-4 text-slate-600"> | |
{cliente.ultimaCompra} | |
</td> | |
<td className="py-3 px-4 text-slate-600"> | |
{cliente.diasInativo} | |
</td> | |
<td className="py-3 px-4"> | |
<Badge | |
variant="outline" | |
className={` | |
${ | |
cliente.potencial === "Alto" | |
? "bg-green-100 text-green-800 border-green-200" | |
: cliente.potencial === "Médio" | |
? "bg-amber-100 text-amber-800 border-amber-200" | |
: "bg-blue-100 text-blue-800 border-blue-200" | |
} | |
`} | |
> | |
{cliente.potencial} | |
</Badge> | |
</td> | |
<td className="py-3 px-4 text-purple-600 font-medium"> | |
{cliente.campanha} | |
</td> | |
<td className="py-3 px-4"> | |
<div className="flex space-x-2"> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fas fa-eye text-slate-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fas fa-paper-plane text-purple-600"></i> | |
</Button> | |
</div> | |
</td> | |
</tr> | |
))} | |
</tbody> | |
</table> | |
</div> | |
<div className="flex justify-between items-center mt-4"> | |
<p className="text-sm text-slate-600"> | |
Mostrando 1-4 de 58 clientes inativos | |
</p> | |
<div className="flex space-x-2"> | |
<Button | |
variant="outline" | |
size="sm" | |
disabled | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
<i className="fas fa-chevron-left mr-1"></i> | |
Anterior | |
</Button> | |
<Button | |
variant="outline" | |
size="sm" | |
className="!rounded-button whitespace-nowrap cursor-pointer" | |
> | |
Próximo | |
<i className="fas fa-chevron-right ml-1"></i> | |
</Button> | |
</div> | |
</div> | |
</CardContent> | |
</Card> | |
<div className="space-y-6"> | |
<Card> | |
<CardHeader className="pb-2"> | |
<CardTitle>Desempenho de Reativação</CardTitle> | |
<CardDescription>Comparativo com metas</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div | |
id="reativacao-chart" | |
style={{ width: "100%", height: "300px" }} | |
></div> | |
</CardContent> | |
</Card> | |
<Card> | |
<CardHeader className="pb-2"> | |
<CardTitle>Campanhas Ativas</CardTitle> | |
<CardDescription> | |
Estratégias de reativação em andamento | |
</CardDescription> | |
</CardHeader> | |
<CardContent> | |
<div className="space-y-4"> | |
<div className="p-3 bg-purple-50 rounded-lg border border-purple-100"> | |
<div className="flex justify-between items-start mb-2"> | |
<div> | |
<h4 className="font-medium text-purple-800"> | |
Desconto 20% Primeira Compra | |
</h4> | |
<p className="text-sm text-purple-600"> | |
Inativos 30-60 dias | |
</p> | |
</div> | |
<Badge className="bg-green-100 text-green-800 border-none"> | |
Ativa | |
</Badge> | |
</div> | |
<div className="flex justify-between text-sm text-purple-700"> | |
<span>32 envios</span> | |
<span>8 conversões (25%)</span> | |
</div> | |
</div> | |
<div className="p-3 bg-blue-50 rounded-lg border border-blue-100"> | |
<div className="flex justify-between items-start mb-2"> | |
<div> | |
<h4 className="font-medium text-blue-800"> | |
Frete Grátis | |
</h4> | |
<p className="text-sm text-blue-600"> | |
Inativos 60-90 dias | |
</p> | |
</div> | |
<Badge className="bg-green-100 text-green-800 border-none"> | |
Ativa | |
</Badge> | |
</div> | |
<div className="flex justify-between text-sm text-blue-700"> | |
<span>45 envios</span> | |
<span>12 conversões (27%)</span> | |
</div> | |
</div> | |
<div className="p-3 bg-amber-50 rounded-lg border border-amber-100"> | |
<div className="flex justify-between items-start mb-2"> | |
<div> | |
<h4 className="font-medium text-amber-800"> | |
Cupom Especial | |
</h4> | |
<p className="text-sm text-amber-600"> | |
Inativos 90-180 dias | |
</p> | |
</div> | |
<Badge className="bg-green-100 text-green-800 border-none"> | |
Ativa | |
</Badge> | |
</div> | |
<div className="flex justify-between text-sm text-amber-700"> | |
<span>28 envios</span> | |
<span>5 conversões (18%)</span> | |
</div> | |
</div> | |
<Button className="w-full !rounded-button whitespace-nowrap cursor-pointer"> | |
<i className="fas fa-plus mr-2"></i> | |
Nova Campanha | |
</Button> | |
</div> | |
</CardContent> | |
</Card> | |
</div> | |
</div> | |
</TabsContent> | |
</Tabs> | |
</main> | |
{/* Footer */} | |
<footer className="bg-white border-t border-slate-200 py-6 mt-8"> | |
<div className="max-w-7xl mx-auto px-4 md:px-6"> | |
<div className="grid grid-cols-1 md:grid-cols-4 gap-8"> | |
<div> | |
<div className="flex items-center mb-4"> | |
<div className="w-8 h-8 rounded-full bg-purple-600 flex items-center justify-center text-white font-bold mr-2"> | |
R | |
</div> | |
<h3 className="text-lg font-bold text-purple-600">Reativou</h3> | |
</div> | |
<p className="text-slate-600 text-sm mb-4"> | |
A plataforma completa para gestão de clientes e reativação de | |
vendas para autônomos e pequenos negócios. | |
</p> | |
<div className="flex space-x-3"> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fab fa-facebook-f text-slate-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fab fa-instagram text-slate-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fab fa-twitter text-slate-600"></i> | |
</Button> | |
<Button | |
variant="ghost" | |
size="sm" | |
className="h-8 w-8 p-0 !rounded-button cursor-pointer" | |
> | |
<i className="fab fa-linkedin-in text-slate-600"></i> | |
</Button> | |
</div> | |
</div> | |
<div> | |
<h4 className="font-medium text-slate-800 mb-4">Recursos</h4> | |
<ul className="space-y-2 text-sm"> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Gestão de Clientes | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Controle de Vendas | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Gestão de Pagamentos | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Estratégias de Reativação | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Relatórios e Análises | |
</a> | |
</li> | |
</ul> | |
</div> | |
<div> | |
<h4 className="font-medium text-slate-800 mb-4">Empresa</h4> | |
<ul className="space-y-2 text-sm"> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Sobre Nós | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Blog | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Carreiras | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Contato | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Parcerias | |
</a> | |
</li> | |
</ul> | |
</div> | |
<div> | |
<h4 className="font-medium text-slate-800 mb-4">Suporte</h4> | |
<ul className="space-y-2 text-sm"> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Central de Ajuda | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Documentação | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Tutoriais | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Status do Sistema | |
</a> | |
</li> | |
<li> | |
<a | |
href="#" | |
className="text-slate-600 hover:text-purple-600 cursor-pointer" | |
> | |
Política de Privacidade | |
</a> | |
</li> | |
</ul> | |
</div> | |
</div> | |
<div className="border-t border-slate-200 mt-8 pt-6 flex flex-col md:flex-row justify-between items-center"> | |
<p className="text-sm text-slate-600 mb-4 md:mb-0"> | |
© 2025 Reativou. Todos os direitos reservados. | |
</p> | |
<div className="flex items-center space-x-4"> | |
<i className="fab fa-cc-visa text-slate-600 text-2xl"></i> | |
<i className="fab fa-cc-mastercard text-slate-600 text-2xl"></i> | |
<i className="fab fa-cc-amex text-slate-600 text-2xl"></i> | |
<i className="fab fa-pix text-slate-600 text-2xl"></i> | |
<i className="fab fa-paypal text-slate-600 text-2xl"></i> | |
</div> | |
</div> | |
</div> | |
</footer> | |
</div> | |
); | |
}; | |
export default App; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment