+
+
@@ -105,7 +109,7 @@ export function VideosCarousel({ itens, className }: MainCarouselProps) {
-
+
diff --git a/src/components/dashboard/weather-widget.tsx b/src/components/dashboard/weather-widget.tsx
index 6ce1186d..17acabe1 100644
--- a/src/components/dashboard/weather-widget.tsx
+++ b/src/components/dashboard/weather-widget.tsx
@@ -1,9 +1,10 @@
"use client"
-import { useEffect, useState } from "react"
+import { useEffect, useState, useMemo } from "react"
import { Cloud, CloudRain, Sun, CloudSun, Droplets, Wind, MapPin } from "lucide-react"
import { Skeleton } from "@/components/ui/skeleton"
import { cn } from "@/lib/utils"
+import { Enterprise } from "@prisma/client"
interface WeatherData {
temperature: number
@@ -16,6 +17,35 @@ interface WeatherData {
interface WeatherWidgetProps {
className?: string
+ enterprise?: Enterprise | null
+}
+
+// Função para obter coordenadas padrão baseadas na empresa
+const getDefaultLocationByEnterprise = (enterprise: Enterprise | null | undefined): { lat: number; lon: number } => {
+ // Tratar null/undefined primeiro
+ if (!enterprise) {
+ return { lat: -29.7175, lon: -52.4258 } // Fallback padrão (Santa Cruz do Sul)
+ }
+
+ // Comparar o valor do enum (Prisma enum é um tipo union de strings literais)
+ // Usar comparação direta com strings, pois o enum Enterprise é equivalente a: "NA" | "Box" | "RHenz" | "Cristallux" | "Box_Filial" | "Cristallux_Filial"
+ if (enterprise === Enterprise.Box || enterprise === Enterprise.RHenz || enterprise === Enterprise.Cristallux) {
+ // Santa Cruz do Sul
+ return { lat: -29.7175, lon: -52.4258 }
+ }
+
+ if (enterprise === Enterprise.Box_Filial) {
+ // Venâncio Aires
+ return { lat: -29.6064, lon: -52.1931 }
+ }
+
+ if (enterprise === Enterprise.Cristallux_Filial) {
+ // Cachoeirinha
+ return { lat: -29.9508, lon: -51.0939 }
+ }
+
+ // Fallback padrão (Santa Cruz do Sul)
+ return { lat: -29.7175, lon: -52.4258 }
}
interface GeocodingResult {
@@ -70,7 +100,7 @@ const getWeatherDescription = (code: number): string => {
return "Condições variáveis"
}
-export function WeatherWidget({ className }: WeatherWidgetProps) {
+export function WeatherWidget({ className, enterprise }: WeatherWidgetProps) {
const [weather, setWeather] = useState
(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
@@ -89,15 +119,17 @@ export function WeatherWidget({ className }: WeatherWidgetProps) {
},
(err) => {
console.error("Erro ao obter localização:", err)
- // Fallback para coordenadas padrão (São Paulo)
- setLocation({ lat: -23.5505, lon: -46.6333 })
+ // Fallback para coordenadas baseadas na empresa
+ const defaultLocation = getDefaultLocationByEnterprise(enterprise)
+ setLocation(defaultLocation)
}
)
} else {
- // Fallback para coordenadas padrão (São Paulo)
- setLocation({ lat: -23.5505, lon: -46.6333 })
+ // Fallback para coordenadas baseadas na empresa
+ const defaultLocation = getDefaultLocationByEnterprise(enterprise)
+ setLocation(defaultLocation)
}
- }, [])
+ }, [enterprise])
// Buscar nome da cidade
useEffect(() => {
@@ -192,6 +224,41 @@ export function WeatherWidget({ className }: WeatherWidgetProps) {
void fetchWeather()
}, [location])
+ // Valores aleatórios para animações (calculados uma vez) - DEVE VIR ANTES DOS EARLY RETURNS
+ const sunParticles = useMemo(() =>
+ Array.from({ length: 15 }).map(() => ({
+ left: Math.random() * 100,
+ top: Math.random() * 100,
+ delay: Math.random() * 3,
+ duration: 3 + Math.random() * 2
+ })), [])
+
+ const windParticles = useMemo(() =>
+ Array.from({ length: 20 }).map(() => ({
+ left: Math.random() * 100,
+ top: Math.random() * 100,
+ duration: 2 + Math.random() * 2,
+ delay: Math.random() * 2,
+ translateX: Math.random() * 50 - 25
+ })), [])
+
+ const windLines = useMemo(() =>
+ Array.from({ length: 8 }).map((_, i) => ({
+ duration: 3 + Math.random() * 2,
+ delay: i * 0.3
+ })), [])
+
+ const cloudPositions = useMemo(() =>
+ Array.from({ length: 3 }).map((_, i) => ({
+ top: 10 + i * 15 + Math.random() * 10,
+ delay: i * 2 + Math.random() * 2
+ })), [])
+
+ const rainDrops = useMemo(() =>
+ Array.from({ length: 30 }).map(() => ({
+ duration: 0.4 + Math.random() * 0.3
+ })), [])
+
if (loading) {
return (
@@ -213,25 +280,149 @@ export function WeatherWidget({ className }: WeatherWidgetProps) {
return null // Não exibe nada em caso de erro
}
+ // Determinar tipo de clima para animações
+ const isSunny = weather.weatherCode === 0
+ const isMostlyClear = weather.weatherCode === 1
+ const isPartlyCloudy = weather.weatherCode === 2
+ const isCloudy = weather.weatherCode === 3
+ const isRainy = weather.weatherCode >= 51 && weather.weatherCode <= 99
+
+ // Gradiente baseado no clima
+ const getGradientClass = () => {
+ if (isSunny) return "bg-gradient-to-br from-yellow-50 via-orange-50 to-yellow-100 dark:from-yellow-950 dark:via-orange-950 dark:to-yellow-900"
+ if (isMostlyClear || isPartlyCloudy) return "bg-gradient-to-br from-blue-50 via-sky-50 to-blue-100 dark:from-blue-950 dark:via-sky-950 dark:to-blue-900"
+ if (isCloudy) return "bg-gradient-to-br from-gray-100 via-gray-200 to-gray-300 dark:from-gray-800 dark:via-gray-700 dark:to-gray-900"
+ if (isRainy) return "bg-gradient-to-br from-blue-50 to-blue-100 dark:from-blue-950 dark:to-blue-900"
+ return "bg-gradient-to-br from-blue-50 to-blue-100 dark:from-blue-950 dark:to-blue-900"
+ }
+
return (
-
- {/* Animação de fundo baseada no clima */}
- {weather.weatherCode >= 51 && weather.weatherCode <= 99 && (
+
+ {/* Animação de chuva */}
+ {isRainy && (
- {Array.from({ length: 30 }).map((_, i) => (
+ {rainDrops.map((drop, i) => (
))}
)}
+
+ {/* Animação de raios de sol para dias ensolarados */}
+ {isSunny && (
+
+ {Array.from({ length: 12 }).map((_, i) => {
+ const angle = (i * 30) * (Math.PI / 180)
+ const radius = 60
+ const x = 50 + Math.cos(angle) * radius
+ const y = 50 + Math.sin(angle) * radius
+ return (
+
+ )
+ })}
+ {/* Partículas de luz flutuantes */}
+ {sunParticles.map((particle, i) => (
+
+ ))}
+
+ )}
+
+ {/* Animação de nuvens e vento para dias nublados */}
+ {(isCloudy || isPartlyCloudy) && (
+
+ {/* Nuvens se movendo */}
+ {cloudPositions.map((cloud, i) => (
+
+
+
+ ))}
+ {/* Partículas de vento */}
+ {windParticles.map((particle, i) => (
+
+ ))}
+ {/* Linhas de vento */}
+ {windLines.map((line, i) => (
+
+ ))}
+
+ )}
+
+ {/* Animação sutil de sol para dias parcialmente nublados */}
+ {(isMostlyClear || isPartlyCloudy) && (
+
+ {Array.from({ length: 8 }).map((_, i) => (
+
+ ))}
+
+ )}
diff --git a/src/styles/globals.css b/src/styles/globals.css
index 812d188b..f1e8c4e4 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -209,6 +209,70 @@
animation: rain linear infinite;
}
+/* Animações adicionais para Widget de Clima */
+@keyframes cloudMove {
+ 0% {
+ transform: translateX(-100px);
+ opacity: 0;
+ }
+ 10% {
+ opacity: 0.2;
+ }
+ 90% {
+ opacity: 0.2;
+ }
+ 100% {
+ transform: translateX(calc(100vw + 100px));
+ opacity: 0;
+ }
+}
+
+@keyframes windParticle {
+ 0% {
+ transform: translateX(0) translateY(0);
+ opacity: 0;
+ }
+ 10% {
+ opacity: 0.3;
+ }
+ 50% {
+ opacity: 0.5;
+ }
+ 90% {
+ opacity: 0.3;
+ }
+ 100% {
+ transform: translateX(50px) translateY(-30px);
+ opacity: 0;
+ }
+}
+
+@keyframes windLine {
+ 0% {
+ transform: translateX(0) scaleX(0.5);
+ opacity: 0.1;
+ }
+ 50% {
+ transform: translateX(20px) scaleX(1);
+ opacity: 0.3;
+ }
+ 100% {
+ transform: translateX(40px) scaleX(0.5);
+ opacity: 0.1;
+ }
+}
+
+@keyframes sunRays {
+ 0%, 100% {
+ opacity: 0.2;
+ transform: rotate(0deg) translateY(-30px) scale(1);
+ }
+ 50% {
+ opacity: 0.4;
+ transform: rotate(180deg) translateY(-30px) scale(1.2);
+ }
+}
+
/* Estilos para Sonner Toaster em mobile */
[data-sonner-toaster] {
z-index: 9999 !important;