feat: updating some fixes

This commit is contained in:
xavidop
2025-06-04 16:08:46 +02:00
parent 1c8653a38a
commit f661f90992
3 changed files with 188 additions and 10 deletions
+173 -3
View File
@@ -1,5 +1,175 @@
# Firebase Studio
# Cardex - Pokémon Card Collection Manager
This is a NextJS starter in Firebase Studio.
A modern web application for managing your Pokémon card collection with AI-powered card scanning and identification.
To get started, take a look at src/app/page.tsx.
## Features
- 🤖 **AI Card Scanning**: Use Gemini Vision to automatically identify Pokémon cards from photos
- 🔐 **Secure Authentication**: Firebase Authentication with email and Google login
- 📱 **Responsive Design**: Modern UI built with Next.js and Tailwind CSS
- 💾 **Cloud Storage**: Real-time data synchronization with Firestore
- ✏️ **CRUD Operations**: Create, read, update, and delete cards in your collection
- 🎯 **Type Safety**: Full TypeScript implementation for better development experience
## Technology Stack
```mermaid
graph TB
subgraph "Frontend"
A[Next.js 15] --> B[React 18]
B --> C[TypeScript]
C --> D[Tailwind CSS]
D --> E[Radix UI Components]
B --> F[React Hook Form]
F --> G[Zod Validation]
end
subgraph "Backend Services"
H[Firebase Auth] --> I[Google Authentication]
J[Firestore Database] --> K[Real-time Updates]
L[Gemini AI] --> M[Vision API]
M --> N[Card Recognition]
end
subgraph "Development Tools"
O[Genkit AI Framework] --> P[AI Flow Management]
Q[ESLint] --> R[Code Quality]
S[PostCSS] --> T[CSS Processing]
end
A --> H
A --> J
A --> L
O --> L
```
## Project Structure
```
src/
├── ai/
│ └── flows/
│ └── scan-pokemon-card.ts # AI card scanning logic
├── app/
│ ├── dashboard/
│ │ ├── collection/ # Card collection pages
│ │ └── scan/ # Card scanning page
│ └── page.tsx # Root page with auth routing
├── components/
│ ├── cards/
│ │ ├── CardForm.tsx # Reusable card form
│ │ ├── CardItem.tsx # Individual card display
│ │ └── CardScanner.tsx # AI scanning component
│ └── ui/ # Reusable UI components
├── hooks/
│ └── useAuth.tsx # Authentication hook
├── lib/
│ ├── firebase.ts # Firebase configuration
│ └── firestore.ts # Database operations
└── types/
└── index.ts # TypeScript type definitions
```
## Getting Started
### Prerequisites
- Node.js 18+
- Firebase project with Firestore and Authentication enabled
- Google AI API key for Gemini Vision
### Installation
1. Clone the repository:
```bash
git clone <repository-url>
cd cardex
```
2. Install dependencies:
```bash
npm install
```
3. Set up environment variables:
```bash
# Create .env.local file with:
NEXT_PUBLIC_FIREBASE_API_KEY=your_firebase_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id
GOOGLE_GENAI_API_KEY=your_gemini_api_key
```
4. Run the development server:
```bash
npm run dev
```
5. (Optional) Start the Genkit AI development server:
```bash
npm run genkit:dev
```
## Usage
### Card Scanning
1. Navigate to the scan page
2. Upload a photo of your Pokémon card
3. Click "Scan Card" to identify the card using AI
4. Review and edit the detected information
5. Save the card to your collection
### Collection Management
- View all your cards in a responsive grid layout
- Edit card details by clicking on any card
- Delete cards from your collection
- Cards are automatically sorted by last updated date
## Database Structure
```
Firestore Collection: users/{userId}/pokemon_cards/{cardId}
├── name: string
├── set: string
├── rarity: string
├── imageDataUrl: string (base64 encoded image)
├── userId: string
├── createdAt: timestamp
└── updatedAt: timestamp
```
## AI Integration
The app uses Google's Gemini Vision API through the Genkit framework to:
- Analyze uploaded card images
- Extract card name, set, and rarity information
- Provide structured data for user review and confirmation
## Contributing
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## Scripts
- `npm run dev` - Start development server with Turbopack
- `npm run build` - Build for production
- `npm run start` - Start production server
- `npm run lint` - Run ESLint
- `npm run typecheck` - Run TypeScript type checking
- `npm run genkit:dev` - Start Genkit AI development server
- `npm run genkit:watch` - Start Genkit with file watching
## License
This project is private and proprietary.
## Support
For support and questions, please open an issue in the repository.
+3 -3
View File
@@ -24,7 +24,7 @@ export type ScanPokemonCardInput = z.infer<typeof ScanPokemonCardInputSchema>;
const ScanPokemonCardOutputSchema = z.object({
cardDetails: z.object({
name: z.string().describe("The name of the Pokemon card.").optional(),
set: z.string().describe("The set the Pokemon card belongs to.").optional(),
set: z.string().describe("The first set the Pokemon card belongs to.").optional(),
rarity: z.string().describe("The rarity of the Pokemon card.").optional(),
}).describe("Details about the Pokemon card.").optional(),
error: z.string().describe("Error message if the card could not be identified.").optional()
@@ -40,14 +40,14 @@ const scanPokemonCardPrompt = ai.definePrompt({
name: 'scanPokemonCardPrompt',
input: {schema: ScanPokemonCardInputSchema},
output: {schema: ScanPokemonCardOutputSchema},
prompt: `You are an expert Pokemon card appraiser. Use the following image to identify the card's name, set, and rarity. If you are unable to determine any of these values, leave them blank.\n
prompt: `You are an expert Pokemon card appraiser. Use the following image to identify the card's name, first set it was introduced in, and rarity. If you are unable to determine any of these values, leave them blank.\n
Photo: {{media url=photoDataUri}}
\n
Respond using the following format:
{
"cardDetails": {
"name": "Pokemon card name",
"set": "Pokemon card set",
"set": "Pokemon first card set it was introduced in",
"rarity": "Pokemon card rarity"
}
}
@@ -10,7 +10,7 @@ import { useToast } from '@/hooks/use-toast';
import { Loader2, AlertTriangle } from 'lucide-react';
export default function EditCardPage() {
const { user } = useAuth();
const { user, loading: authLoading } = useAuth();
const router = useRouter();
const params = useParams();
const cardId = params.cardId as string;
@@ -22,6 +22,16 @@ export default function EditCardPage() {
const { toast } = useToast();
useEffect(() => {
// Don't do anything while auth is still loading
if (authLoading) return;
// Redirect if no user
if (!user) {
router.replace('/login');
return;
}
// Only fetch card if we have user and cardId
if (user && cardId) {
setLoading(true);
setError(null);
@@ -40,10 +50,8 @@ export default function EditCardPage() {
toast({ title: "Error", description: "Failed to load card details.", variant: "destructive" });
})
.finally(() => setLoading(false));
} else if (!user && !loading) { // if auth is loaded and no user
router.replace('/login');
}
}, [user, cardId, router, toast, loading]);
}, [user, cardId, router, toast, authLoading]); // Removed 'loading' from dependencies
const handleUpdateCard = async (data: CardFormInputs) => {
if (!user || !card) return;