imports nao usados

This commit is contained in:
Gabriel Santana de Menezes 2026-05-04 21:02:44 -04:00
parent 7c4884b6ad
commit 880d72d5d6
2 changed files with 193 additions and 104 deletions

View file

@ -7,7 +7,6 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import net.beetechgroup.beetask.entities.task.Task; import net.beetechgroup.beetask.entities.task.Task;
import net.beetechgroup.beetask.entities.task.TaskHistoryItem; import net.beetechgroup.beetask.entities.task.TaskHistoryItem;

View file

@ -1,5 +1,5 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { motion, AnimatePresence } from "framer-motion"; import { motion } from "framer-motion";
import { import {
BarChart3, BarChart3,
Calendar, Calendar,
@ -13,11 +13,13 @@ import {
Download, Download,
AlertCircle, AlertCircle,
Loader2, Loader2,
ArrowUpRight,
History, History,
Briefcase Briefcase,
} from "lucide-react"; } from "lucide-react";
import { dashboardService, type DashboardData } from "../services/dashboardService"; import {
dashboardService,
type DashboardData,
} from "../services/dashboardService";
import { cn } from "../lib/utils"; import { cn } from "../lib/utils";
import { format, subDays, startOfMonth, endOfMonth } from "date-fns"; import { format, subDays, startOfMonth, endOfMonth } from "date-fns";
import { ptBR } from "date-fns/locale"; import { ptBR } from "date-fns/locale";
@ -34,7 +36,7 @@ export const DashboardPage: React.FC = () => {
try { try {
const result = await dashboardService.getDashboard( const result = await dashboardService.getDashboard(
startDate.toISOString(), startDate.toISOString(),
endDate.toISOString() endDate.toISOString(),
); );
setData(result); setData(result);
} catch (err) { } catch (err) {
@ -77,7 +79,7 @@ export const DashboardPage: React.FC = () => {
<Calendar size={18} className="text-brand" /> <Calendar size={18} className="text-brand" />
<input <input
type="date" type="date"
value={format(startDate, 'yyyy-MM-dd')} value={format(startDate, "yyyy-MM-dd")}
onChange={(e) => setStartDate(new Date(e.target.value))} onChange={(e) => setStartDate(new Date(e.target.value))}
className="bg-transparent border-none text-sm font-bold text-text-main focus:ring-0 outline-none" className="bg-transparent border-none text-sm font-bold text-text-main focus:ring-0 outline-none"
/> />
@ -85,7 +87,7 @@ export const DashboardPage: React.FC = () => {
<div className="flex items-center gap-2 px-3 py-2"> <div className="flex items-center gap-2 px-3 py-2">
<input <input
type="date" type="date"
value={format(endDate, 'yyyy-MM-dd')} value={format(endDate, "yyyy-MM-dd")}
onChange={(e) => setEndDate(new Date(e.target.value))} onChange={(e) => setEndDate(new Date(e.target.value))}
className="bg-transparent border-none text-sm font-bold text-text-main focus:ring-0 outline-none" className="bg-transparent border-none text-sm font-bold text-text-main focus:ring-0 outline-none"
/> />
@ -107,9 +109,14 @@ export const DashboardPage: React.FC = () => {
) : error ? ( ) : error ? (
<div className="flex flex-col items-center justify-center min-h-[50vh] text-center p-6 bg-surface rounded-[2.5rem] border border-border-soft"> <div className="flex flex-col items-center justify-center min-h-[50vh] text-center p-6 bg-surface rounded-[2.5rem] border border-border-soft">
<AlertCircle size={48} className="text-rose-500 mb-4" /> <AlertCircle size={48} className="text-rose-500 mb-4" />
<h3 className="text-xl font-bold text-text-main mb-2">Ocorreu um erro</h3> <h3 className="text-xl font-bold text-text-main mb-2">
Ocorreu um erro
</h3>
<p className="text-text-muted max-w-sm mb-6">{error}</p> <p className="text-text-muted max-w-sm mb-6">{error}</p>
<button onClick={fetchDashboardData} className="px-6 py-3 bg-brand text-white rounded-xl font-bold hover:bg-brand-dark transition-all"> <button
onClick={fetchDashboardData}
className="px-6 py-3 bg-brand text-white rounded-xl font-bold hover:bg-brand-dark transition-all"
>
Tentar novamente Tentar novamente
</button> </button>
</div> </div>
@ -126,14 +133,21 @@ export const DashboardPage: React.FC = () => {
<div className="w-12 h-12 bg-brand/10 text-brand rounded-xl flex items-center justify-center mb-6"> <div className="w-12 h-12 bg-brand/10 text-brand rounded-xl flex items-center justify-center mb-6">
<Clock size={24} /> <Clock size={24} />
</div> </div>
<div className="text-sm font-bold text-text-muted uppercase tracking-wider">Tempo Total</div> <div className="text-sm font-bold text-text-muted uppercase tracking-wider">
<div className="mt-2 text-4xl font-black text-text-main">{formatMinutes(data.totalMinutesWorked)}</div> Tempo Total
</div>
<div className="mt-2 text-4xl font-black text-text-main">
{formatMinutes(data.totalMinutesWorked)}
</div>
<div className="mt-4 flex items-center gap-1.5 text-[10px] font-black text-brand bg-brand/5 w-fit px-2 py-1 rounded-full uppercase tracking-widest"> <div className="mt-4 flex items-center gap-1.5 text-[10px] font-black text-brand bg-brand/5 w-fit px-2 py-1 rounded-full uppercase tracking-widest">
<TrendingUp size={12} /> <TrendingUp size={12} />
Foco em alta Foco em alta
</div> </div>
</div> </div>
<Clock size={120} className="absolute -right-10 -bottom-10 text-brand/5 -rotate-12 transition-transform group-hover:rotate-0" /> <Clock
size={120}
className="absolute -right-10 -bottom-10 text-brand/5 -rotate-12 transition-transform group-hover:rotate-0"
/>
</motion.div> </motion.div>
<motion.div <motion.div
@ -146,14 +160,21 @@ export const DashboardPage: React.FC = () => {
<div className="w-12 h-12 bg-accent/10 text-accent rounded-xl flex items-center justify-center mb-6"> <div className="w-12 h-12 bg-accent/10 text-accent rounded-xl flex items-center justify-center mb-6">
<CheckCircle2 size={24} /> <CheckCircle2 size={24} />
</div> </div>
<div className="text-sm font-bold text-text-muted uppercase tracking-wider">Tarefas Concluídas</div> <div className="text-sm font-bold text-text-muted uppercase tracking-wider">
<div className="mt-2 text-4xl font-black text-text-main">{data.finishedTasksInPeriod.length}</div> Tarefas Concluídas
</div>
<div className="mt-2 text-4xl font-black text-text-main">
{data.finishedTasksInPeriod.length}
</div>
<div className="mt-4 flex items-center gap-1.5 text-[10px] font-black text-accent bg-accent/5 w-fit px-2 py-1 rounded-full uppercase tracking-widest"> <div className="mt-4 flex items-center gap-1.5 text-[10px] font-black text-accent bg-accent/5 w-fit px-2 py-1 rounded-full uppercase tracking-widest">
<CheckCircle2 size={12} /> <CheckCircle2 size={12} />
Periodo de Entrega Periodo de Entrega
</div> </div>
</div> </div>
<CheckCircle2 size={120} className="absolute -right-10 -bottom-10 text-accent/5 -rotate-12 transition-transform group-hover:rotate-0" /> <CheckCircle2
size={120}
className="absolute -right-10 -bottom-10 text-accent/5 -rotate-12 transition-transform group-hover:rotate-0"
/>
</motion.div> </motion.div>
<motion.div <motion.div
@ -166,18 +187,27 @@ export const DashboardPage: React.FC = () => {
<div className="w-12 h-12 bg-white/20 text-white rounded-xl flex items-center justify-center mb-6"> <div className="w-12 h-12 bg-white/20 text-white rounded-xl flex items-center justify-center mb-6">
<FileText size={24} /> <FileText size={24} />
</div> </div>
<div className="text-sm font-bold text-white/70 uppercase tracking-wider">Média por Projeto</div> <div className="text-sm font-bold text-white/70 uppercase tracking-wider">
Média por Projeto
</div>
<div className="mt-2 text-4xl font-black"> <div className="mt-2 text-4xl font-black">
{data.projectStats.length > 0 {data.projectStats.length > 0
? formatMinutes(Math.round(data.totalMinutesWorked / data.projectStats.length)) ? formatMinutes(
: '0h 0m'} Math.round(
data.totalMinutesWorked / data.projectStats.length,
),
)
: "0h 0m"}
</div> </div>
<button className="mt-6 inline-flex items-center gap-2 text-xs font-black uppercase tracking-widest bg-white/10 hover:bg-white/20 px-4 py-2 rounded-xl transition-all"> <button className="mt-6 inline-flex items-center gap-2 text-xs font-black uppercase tracking-widest bg-white/10 hover:bg-white/20 px-4 py-2 rounded-xl transition-all">
<Download size={14} /> <Download size={14} />
Exportar Relatório Exportar Relatório
</button> </button>
</div> </div>
<TrendingUp size={160} className="absolute -right-10 -bottom-10 text-white/10 -rotate-12 transition-transform group-hover:rotate-0" /> <TrendingUp
size={160}
className="absolute -right-10 -bottom-10 text-white/10 -rotate-12 transition-transform group-hover:rotate-0"
/>
</motion.div> </motion.div>
</div> </div>
@ -187,34 +217,51 @@ export const DashboardPage: React.FC = () => {
<div className="flex items-center justify-between mb-8"> <div className="flex items-center justify-between mb-8">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Briefcase size={20} className="text-brand" /> <Briefcase size={20} className="text-brand" />
<h2 className="text-xl font-black text-text-main">Tempo por Projeto</h2> <h2 className="text-xl font-black text-text-main">
Tempo por Projeto
</h2>
</div> </div>
<BarChart3 size={20} className="text-text-muted" /> <BarChart3 size={20} className="text-text-muted" />
</div> </div>
<div className="space-y-6"> <div className="space-y-6">
{data.projectStats.length > 0 ? data.projectStats.map((stat, idx) => { {data.projectStats.length > 0 ? (
const percentage = (stat.totalMinutes / data.totalMinutesWorked) * 100; data.projectStats.map((stat, idx) => {
const percentage =
(stat.totalMinutes / data.totalMinutesWorked) * 100;
return ( return (
<div key={stat.projectId} className="space-y-2"> <div key={stat.projectId} className="space-y-2">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="font-bold text-text-main flex items-center gap-2"> <span className="font-bold text-text-main flex items-center gap-2">
<div className={cn("w-2 h-2 rounded-full", idx % 2 === 0 ? "bg-brand" : "bg-accent")} /> <div
className={cn(
"w-2 h-2 rounded-full",
idx % 2 === 0 ? "bg-brand" : "bg-accent",
)}
/>
{stat.projectName} {stat.projectName}
</span> </span>
<span className="text-sm font-black text-text-muted">{formatMinutes(stat.totalMinutes)}</span> <span className="text-sm font-black text-text-muted">
{formatMinutes(stat.totalMinutes)}
</span>
</div> </div>
<div className="h-3 w-full bg-surface-muted rounded-full overflow-hidden"> <div className="h-3 w-full bg-surface-muted rounded-full overflow-hidden">
<motion.div <motion.div
initial={{ width: 0 }} initial={{ width: 0 }}
animate={{ width: `${percentage}%` }} animate={{ width: `${percentage}%` }}
className={cn("h-full rounded-full", idx % 2 === 0 ? "bg-brand" : "bg-accent")} className={cn(
"h-full rounded-full",
idx % 2 === 0 ? "bg-brand" : "bg-accent",
)}
/> />
</div> </div>
</div> </div>
); );
}) : ( })
<div className="text-center py-10 opacity-50 font-bold">Nenhum dado por projeto.</div> ) : (
<div className="text-center py-10 opacity-50 font-bold">
Nenhum dado por projeto.
</div>
)} )}
</div> </div>
</section> </section>
@ -224,29 +271,45 @@ export const DashboardPage: React.FC = () => {
<div className="flex items-center justify-between mb-8"> <div className="flex items-center justify-between mb-8">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<History size={20} className="text-accent" /> <History size={20} className="text-accent" />
<h2 className="text-xl font-black text-text-main">Daily (Ontem)</h2> <h2 className="text-xl font-black text-text-main">
Daily (Ontem)
</h2>
</div> </div>
<div className="text-xs font-bold text-text-muted uppercase bg-surface-muted px-2 py-1 rounded-lg"> <div className="text-xs font-bold text-text-muted uppercase bg-surface-muted px-2 py-1 rounded-lg">
{format(subDays(new Date(), 1), 'dd MMM', { locale: ptBR })} {format(subDays(new Date(), 1), "dd MMM", { locale: ptBR })}
</div> </div>
</div> </div>
<div className="space-y-4 max-h-[300px] overflow-y-auto pr-2 custom-scrollbar"> <div className="space-y-4 max-h-[300px] overflow-y-auto pr-2 custom-scrollbar">
{data.yesterdayTasks.length > 0 ? data.yesterdayTasks.map(task => ( {data.yesterdayTasks.length > 0 ? (
<div key={task.id} className="flex items-center justify-between p-4 bg-app-bg rounded-2xl border border-border-soft group hover:border-brand/30 transition-all"> data.yesterdayTasks.map((task) => (
<div
key={task.id}
className="flex items-center justify-between p-4 bg-app-bg rounded-2xl border border-border-soft group hover:border-brand/30 transition-all"
>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="w-10 h-10 bg-brand/10 text-brand rounded-xl flex items-center justify-center shrink-0"> <div className="w-10 h-10 bg-brand/10 text-brand rounded-xl flex items-center justify-center shrink-0">
<Layout size={18} /> <Layout size={18} />
</div> </div>
<div> <div>
<div className="font-bold text-text-main line-clamp-1">{task.title}</div> <div className="font-bold text-text-main line-clamp-1">
<div className="text-[10px] font-black uppercase text-brand tracking-widest">{task.projectName}</div> {task.title}
</div>
<div className="text-[10px] font-black uppercase text-brand tracking-widest">
{task.projectName}
</div> </div>
</div> </div>
<ChevronRight size={16} className="text-text-muted group-hover:translate-x-1 transition-transform" />
</div> </div>
)) : ( <ChevronRight
<div className="text-center py-10 opacity-50 font-bold">Nenhuma atividade registrada ontem.</div> size={16}
className="text-text-muted group-hover:translate-x-1 transition-transform"
/>
</div>
))
) : (
<div className="text-center py-10 opacity-50 font-bold">
Nenhuma atividade registrada ontem.
</div>
)} )}
</div> </div>
</section> </section>
@ -257,7 +320,9 @@ export const DashboardPage: React.FC = () => {
<div className="flex items-center justify-between mb-8"> <div className="flex items-center justify-between mb-8">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<FileText size={20} className="text-brand" /> <FileText size={20} className="text-brand" />
<h2 className="text-xl font-black text-text-main">Relatório de Entregas</h2> <h2 className="text-xl font-black text-text-main">
Relatório de Entregas
</h2>
</div> </div>
<button className="flex items-center gap-2 text-sm font-bold text-brand hover:underline bg-brand/5 px-4 py-2 rounded-xl transition-all"> <button className="flex items-center gap-2 text-sm font-bold text-brand hover:underline bg-brand/5 px-4 py-2 rounded-xl transition-all">
<Download size={16} /> <Download size={16} />
@ -269,23 +334,42 @@ export const DashboardPage: React.FC = () => {
<table className="w-full text-left"> <table className="w-full text-left">
<thead> <thead>
<tr className="border-b border-border-soft"> <tr className="border-b border-border-soft">
<th className="pb-4 text-xs font-black uppercase text-text-muted tracking-widest pl-4">Tarefa</th> <th className="pb-4 text-xs font-black uppercase text-text-muted tracking-widest pl-4">
<th className="pb-4 text-xs font-black uppercase text-text-muted tracking-widest">Projeto</th> Tarefa
<th className="pb-4 text-xs font-black uppercase text-text-muted tracking-widest">Concluída em</th> </th>
<th className="pb-4 text-xs font-black uppercase text-text-muted tracking-widest text-right pr-4">Status</th> <th className="pb-4 text-xs font-black uppercase text-text-muted tracking-widest">
Projeto
</th>
<th className="pb-4 text-xs font-black uppercase text-text-muted tracking-widest">
Concluída em
</th>
<th className="pb-4 text-xs font-black uppercase text-text-muted tracking-widest text-right pr-4">
Status
</th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-border-soft/50"> <tbody className="divide-y divide-border-soft/50">
{data.finishedTasksInPeriod.length > 0 ? data.finishedTasksInPeriod.map(task => ( {data.finishedTasksInPeriod.length > 0 ? (
<tr key={task.id} className="group hover:bg-app-bg transition-colors"> data.finishedTasksInPeriod.map((task) => (
<td className="py-4 pl-4 font-bold text-text-main">{task.title}</td> <tr
key={task.id}
className="group hover:bg-app-bg transition-colors"
>
<td className="py-4 pl-4 font-bold text-text-main">
{task.title}
</td>
<td className="py-4 text-sm font-medium text-text-muted"> <td className="py-4 text-sm font-medium text-text-muted">
<span className="px-2 py-1 bg-surface-muted rounded-lg border border-border-soft"> <span className="px-2 py-1 bg-surface-muted rounded-lg border border-border-soft">
{task.projectName} {task.projectName}
</span> </span>
</td> </td>
<td className="py-4 text-sm font-bold text-text-main"> <td className="py-4 text-sm font-bold text-text-main">
{task.finishedAt ? format(new Date(task.finishedAt), 'dd/MM/yyyy HH:mm') : '-'} {task.finishedAt
? format(
new Date(task.finishedAt),
"dd/MM/yyyy HH:mm",
)
: "-"}
</td> </td>
<td className="py-4 text-right pr-4"> <td className="py-4 text-right pr-4">
<span className="inline-flex items-center gap-1 rounded-lg bg-green-500/10 px-2 py-1 text-[10px] font-black uppercase text-green-600 tracking-tighter"> <span className="inline-flex items-center gap-1 rounded-lg bg-green-500/10 px-2 py-1 text-[10px] font-black uppercase text-green-600 tracking-tighter">
@ -294,9 +378,15 @@ export const DashboardPage: React.FC = () => {
</span> </span>
</td> </td>
</tr> </tr>
)) : ( ))
) : (
<tr> <tr>
<td colSpan={4} className="py-10 text-center opacity-50 font-bold">Nenhuma tarefa finalizada neste período.</td> <td
colSpan={4}
className="py-10 text-center opacity-50 font-bold"
>
Nenhuma tarefa finalizada neste período.
</td>
</tr> </tr>
)} )}
</tbody> </tbody>