correção da tela branca

This commit is contained in:
João Vitor 2025-11-25 12:25:51 -03:00
parent b793f7dca4
commit 9ec05a0599
6 changed files with 2757 additions and 211 deletions

92
App.tsx
View file

@ -1,48 +1,47 @@
import React, { useState, useEffect } from "react";
import React, { useState, useEffect } from 'react'; import { Navbar } from "./components/Navbar";
import { Navbar } from './components/Navbar'; import { Home } from "./pages/Home";
import { Home } from './pages/Home'; import { Dashboard } from "./pages/Dashboard";
import { Dashboard } from './pages/Dashboard'; import { Login } from "./pages/Login";
import { Login } from './pages/Login'; import { AuthProvider, useAuth } from "./contexts/AuthContext";
import { AuthProvider, useAuth } from './contexts/AuthContext'; import { DataProvider } from "./contexts/DataContext";
import { DataProvider } from './contexts/DataContext'; import { Construction } from "lucide-react";
import { Construction } from 'lucide-react'; // Placeholder icon
const AppContent: React.FC = () => { const AppContent: React.FC = () => {
const { user } = useAuth(); const { user } = useAuth();
const [currentPage, setCurrentPage] = useState('home'); const [currentPage, setCurrentPage] = useState("home");
useEffect(() => { useEffect(() => {
if (user && currentPage === 'login') { if (user && currentPage === "login") {
setCurrentPage('dashboard'); setCurrentPage("dashboard");
} }
}, [user, currentPage]); }, [user, currentPage]);
// Simple Router Logic
const renderPage = () => { const renderPage = () => {
if (currentPage === 'home') return <Home onEnter={() => setCurrentPage(user ? 'dashboard' : 'login')} />; if (currentPage === "home")
if (currentPage === 'login') return user ? <Dashboard /> : <Login />; return (
<Home onEnter={() => setCurrentPage(user ? "dashboard" : "login")} />
);
if (currentPage === "login") return user ? <Dashboard /> : <Login />;
// Protected Routes Check
if (!user) return <Login />; if (!user) return <Login />;
switch (currentPage) { switch (currentPage) {
case 'dashboard': case "dashboard":
case 'events': case "events":
return <Dashboard initialView="list" />; return <Dashboard initialView="list" />;
case 'request-event': case "request-event":
return <Dashboard initialView="create" />; return <Dashboard initialView="create" />;
case 'uploads': case "uploads":
return <Dashboard initialView="uploads" />; return <Dashboard initialView="uploads" />;
// Placeholder routes for future implementation case "team":
case 'team': case "finance":
case 'finance': case "settings":
case 'settings': case "albums":
case 'albums': case "calendar":
case 'calendar':
return ( return (
<div className="min-h-screen bg-white pt-32 px-4 text-center fade-in"> <div className="min-h-screen bg-white pt-32 px-4 text-center fade-in">
<div className="max-w-md mx-auto bg-gray-50 p-12 rounded-lg border border-gray-100 shadow-sm"> <div className="max-w-md mx-auto bg-gray-50 p-12 rounded-lg border border-gray-100 shadow-sm">
@ -50,16 +49,20 @@ const AppContent: React.FC = () => {
<Construction size={32} /> <Construction size={32} />
</div> </div>
<h2 className="text-2xl font-serif font-bold mb-3 text-brand-black capitalize"> <h2 className="text-2xl font-serif font-bold mb-3 text-brand-black capitalize">
{currentPage === 'team' ? 'Equipe & Fotógrafos' : {currentPage === "team"
currentPage === 'finance' ? 'Financeiro' : ? "Equipe & Fotógrafos"
currentPage === 'calendar' ? 'Agenda' : : currentPage === "finance"
currentPage} ? "Financeiro"
: currentPage === "calendar"
? "Agenda"
: currentPage}
</h2> </h2>
<p className="text-gray-500 mb-8 leading-relaxed"> <p className="text-gray-500 mb-8 leading-relaxed">
Esta funcionalidade está em desenvolvimento e estará disponível em breve no seu painel. Esta funcionalidade está em desenvolvimento e estará disponível
em breve no seu painel.
</p> </p>
<button <button
onClick={() => setCurrentPage('dashboard')} onClick={() => setCurrentPage("dashboard")}
className="px-6 py-2 bg-brand-black text-white rounded-sm hover:bg-gray-800 transition-colors font-medium text-sm" className="px-6 py-2 bg-brand-black text-white rounded-sm hover:bg-gray-800 transition-colors font-medium text-sm"
> >
Voltar ao Dashboard Voltar ao Dashboard
@ -69,30 +72,29 @@ const AppContent: React.FC = () => {
); );
default: default:
// Fallback
return <Dashboard initialView="list" />; return <Dashboard initialView="list" />;
} }
}; };
return ( return (
<div className="min-h-screen bg-white"> <div className="min-h-screen bg-white">
<Navbar <Navbar onNavigate={setCurrentPage} currentPage={currentPage} />
onNavigate={setCurrentPage} <main>{renderPage()}</main>
currentPage={currentPage}
/>
<main>
{renderPage()}
</main>
{/* Footer only on Home */} {currentPage === "home" && (
{currentPage === 'home' && (
<footer className="bg-white border-t border-gray-100 py-12"> <footer className="bg-white border-t border-gray-100 py-12">
<div className="max-w-7xl mx-auto px-4 flex flex-col md:flex-row justify-between items-center text-sm text-gray-500"> <div className="max-w-7xl mx-auto px-4 flex flex-col md:flex-row justify-between items-center text-sm text-gray-500">
<p>&copy; 2024 PhotumManager. Todos os direitos reservados.</p> <p>&copy; 2024 PhotumManager. Todos os direitos reservados.</p>
<div className="flex space-x-6 mt-4 md:mt-0"> <div className="flex space-x-6 mt-4 md:mt-0">
<a href="#" className="hover:text-brand-black">Política de Privacidade</a> <a href="#" className="hover:text-brand-black">
<a href="#" className="hover:text-brand-black">Termos de Uso</a> Política de Privacidade
<a href="#" className="hover:text-brand-black">Instagram</a> </a>
<a href="#" className="hover:text-brand-black">
Termos de Uso
</a>
<a href="#" className="hover:text-brand-black">
Instagram
</a>
</div> </div>
</div> </div>
</footer> </footer>

View file

@ -1,11 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="pt-BR"> <html lang="pt-BR">
<head>
<head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PhotumManager - Gestão de Eventos</title> <title>PhotumManager - Gestão de Eventos</title>
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,600;1,400&display=swap" rel="stylesheet"> <link
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,600;1,400&display=swap"
rel="stylesheet">
<script> <script>
tailwind.config = { tailwind.config = {
theme: { theme: {
@ -17,7 +20,7 @@
colors: { colors: {
brand: { brand: {
black: '#1a1a1a', black: '#1a1a1a',
gold: '#B9CF33', // Updated from #c5a059 to #B9CF33 gold: '#B9CF33',
gray: '#f4f4f4', gray: '#f4f4f4',
darkgray: '#333333' darkgray: '#333333'
} }
@ -27,33 +30,62 @@
} }
</script> </script>
<style> <style>
/* Smooth scrolling */ html {
html { scroll-behavior: smooth; } scroll-behavior: smooth;
/* Custom scrollbar */
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-track { background: #f1f1f1; }
::-webkit-scrollbar-thumb { background: #B9CF33; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #a5bd2e; }
.fade-in { animation: fadeIn 0.5s ease-out forwards; }
.slide-up { animation: slideUp 0.6s ease-out forwards; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
</style>
<script type="importmap">
{
"imports": {
"react/": "https://aistudiocdn.com/react@^19.2.0/",
"react": "https://aistudiocdn.com/react@^19.2.0",
"lucide-react": "https://aistudiocdn.com/lucide-react@^0.554.0",
"react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
"@google/genai": "https://aistudiocdn.com/@google/genai@^1.30.0"
} }
}
</script> ::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
}
::-webkit-scrollbar-thumb {
background: #B9CF33;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #a5bd2e;
}
.fade-in {
animation: fadeIn 0.5s ease-out forwards;
}
.slide-up {
animation: slideUp 0.6s ease-out forwards;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head> </head>
<body class="bg-white text-brand-black antialiased selection:bg-brand-gold selection:text-white">
<body class="bg-white text-brand-black antialiased selection:bg-brand-gold selection:text-white">
<div id="root"></div> <div id="root"></div>
</body> <script type="module" src="/index.tsx"></script>
</body>
</html> </html>

View file

@ -1,10 +1,10 @@
import React from 'react'; import React from "react";
import ReactDOM from 'react-dom/client'; import ReactDOM from "react-dom/client";
import App from './App'; import App from "./App";
const rootElement = document.getElementById('root'); const rootElement = document.getElementById("root");
if (!rootElement) { if (!rootElement) {
throw new Error("Could not find root element to mount to"); throw new Error("Could not find root element");
} }
const root = ReactDOM.createRoot(rootElement); const root = ReactDOM.createRoot(rootElement);

2588
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -9,10 +9,10 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"react": "^19.2.0", "@google/genai": "^1.30.0",
"lucide-react": "^0.554.0", "lucide-react": "^0.554.0",
"react-dom": "^19.2.0", "react": "^19.2.0",
"@google/genai": "^1.30.0" "react-dom": "^19.2.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.14.0", "@types/node": "^22.14.0",

View file

@ -1,6 +1,6 @@
import { GoogleGenAI } from "@google/genai"; // Gemini API service temporarily disabled - requires API key configuration
// import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({ apiKey: process.env.API_KEY }); // const ai = new GoogleGenAI({ apiKey: process.env.API_KEY });
export interface GeoResult { export interface GeoResult {
street: string; street: string;
@ -12,88 +12,12 @@ export interface GeoResult {
mapLink?: string; mapLink?: string;
} }
export const searchLocationWithGemini = async (query: string): Promise<GeoResult[]> => { // Temporarily disabled - requires API key setup
if (!query || query.length < 3) return []; export const searchLocationWithGemini = async (
query: string
try { ): Promise<GeoResult[]> => {
// Attempt to get user location for better context console.warn(
let userLocation: { latitude: number; longitude: number } | undefined; "Gemini location search is disabled. Please configure API key to enable."
try { );
const position = await new Promise<GeolocationPosition>((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, { timeout: 2000 });
});
userLocation = {
latitude: position.coords.latitude,
longitude: position.coords.longitude
};
} catch (e) {
// Ignore geolocation errors, proceed without it
}
const response = await ai.models.generateContent({
model: 'gemini-2.5-flash',
contents: `Find the specific address details for the location query: "${query}".
You MUST return the address components in the following format (one per line):
Description: [A concise formatted address]
Street: [Street Name]
Number: [Street Number, if available]
City: [City Name]
State: [State Code, e.g., SP, RJ]
Zip: [Postal Code]
If a specific component is not found, leave it empty after the colon.`,
config: {
tools: [{ googleMaps: {} }],
toolConfig: userLocation ? {
retrievalConfig: {
latLng: {
latitude: userLocation.latitude,
longitude: userLocation.longitude
}
}
} : undefined
}
});
const text = response.text || "";
// Helper parser
const parseField = (key: string) => {
const regex = new RegExp(`${key}:\\s*(.*)`, 'i');
const match = text.match(regex);
return match ? match[1].trim() : '';
};
// Extract Google Maps URI from grounding metadata
let mapUri = '';
const chunks = response.candidates?.[0]?.groundingMetadata?.groundingChunks || [];
// Look for the Web URI in the chunks (Google Maps grounding often returns this)
for (const chunk of chunks) {
if (chunk.web?.uri && (chunk.web.uri.includes('google.com/maps') || chunk.web.uri.includes('maps.google.com'))) {
mapUri = chunk.web.uri;
break;
}
}
const result: GeoResult = {
street: parseField('Street'),
number: parseField('Number'),
city: parseField('City'),
state: parseField('State'),
zip: parseField('Zip'),
description: parseField('Description') || text.split('\n')[0], // Fallback to first line
mapLink: mapUri
};
// Filter out bad results (empty city/state usually means it failed to identify a place)
if (!result.city && !result.street) return [];
return [result];
} catch (error) {
console.error("Gemini Search Error:", error);
return []; return [];
}
}; };