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

122
App.tsx
View file

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

View file

@ -1,59 +1,91 @@
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PhotumManager - Gestão de Eventos</title>
<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">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
serif: ['Playfair Display', 'serif'],
},
colors: {
brand: {
black: '#1a1a1a',
gold: '#B9CF33', // Updated from #c5a059 to #B9CF33
gray: '#f4f4f4',
darkgray: '#333333'
}
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PhotumManager - Gestão de Eventos</title>
<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">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
serif: ['Playfair Display', 'serif'],
},
colors: {
brand: {
black: '#1a1a1a',
gold: '#B9CF33',
gray: '#f4f4f4',
darkgray: '#333333'
}
}
}
}
</script>
<style>
/* Smooth scrolling */
html { 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; }
}
</script>
<style>
html {
scroll-behavior: smooth;
}
.fade-in { animation: fadeIn 0.5s ease-out forwards; }
.slide-up { animation: slideUp 0.6s ease-out forwards; }
::-webkit-scrollbar {
width: 8px;
}
@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-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>
<body class="bg-white text-brand-black antialiased selection:bg-brand-gold selection:text-white">
<div id="root"></div>
</body>
<body class="bg-white text-brand-black antialiased selection:bg-brand-gold selection:text-white">
<div id="root"></div>
<script type="module" src="/index.tsx"></script>
</body>
</html>

View file

@ -1,10 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const rootElement = document.getElementById('root');
const rootElement = document.getElementById("root");
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);

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"
},
"dependencies": {
"react": "^19.2.0",
"@google/genai": "^1.30.0",
"lucide-react": "^0.554.0",
"react-dom": "^19.2.0",
"@google/genai": "^1.30.0"
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"devDependencies": {
"@types/node": "^22.14.0",

View file

@ -1,6 +1,6 @@
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({ apiKey: process.env.API_KEY });
// Gemini API service temporarily disabled - requires API key configuration
// import { GoogleGenAI } from "@google/genai";
// const ai = new GoogleGenAI({ apiKey: process.env.API_KEY });
export interface GeoResult {
street: string;
@ -12,88 +12,12 @@ export interface GeoResult {
mapLink?: string;
}
export const searchLocationWithGemini = async (query: string): Promise<GeoResult[]> => {
if (!query || query.length < 3) return [];
try {
// Attempt to get user location for better context
let userLocation: { latitude: number; longitude: number } | undefined;
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 [];
}
// Temporarily disabled - requires API key setup
export const searchLocationWithGemini = async (
query: string
): Promise<GeoResult[]> => {
console.warn(
"Gemini location search is disabled. Please configure API key to enable."
);
return [];
};