✨ Features: - Camera OCR card scanning with Tesseract.js - Beautiful glowing card effects and animations - Intelligent card matching and recognition - Mobile-responsive design with Tailwind CSS 🏗️ Architecture: - Frontend: React TypeScript application - Backend: Vercel Functions (replacing FastAPI) - Database: JSON file with exported card data - Deployment: Single Vercel project 📁 Structure: - api/ - Vercel Functions backend endpoints - src/ - React frontend components and logic - src/data/cards.json - Card database (12 cards) - vercel.json - Optimized Vercel configuration 💰 Cost: /bin/zsh additional (uses existing Vercel Pro) 🚀 Ready for immediate Vercel deployment
110 lines
No EOL
2.8 KiB
TypeScript
110 lines
No EOL
2.8 KiB
TypeScript
import axios from 'axios';
|
|
import { API_BASE_URL } from '../config/api';
|
|
|
|
// Create axios instance with base configuration
|
|
const api = axios.create({
|
|
baseURL: API_BASE_URL,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
// Add request interceptor to include auth token
|
|
api.interceptors.request.use(
|
|
(config) => {
|
|
const token = localStorage.getItem('tcg_vault_token');
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`;
|
|
}
|
|
return config;
|
|
},
|
|
(error) => {
|
|
return Promise.reject(error);
|
|
}
|
|
);
|
|
|
|
// API service functions
|
|
export const cardService = {
|
|
getAllCards: async (params?: { game?: string; search?: string; skip?: number; limit?: number }) => {
|
|
const response = await api.get('/cards/', { params });
|
|
return response.data;
|
|
},
|
|
|
|
getCard: async (cardId: number) => {
|
|
const response = await api.get(`/cards/${cardId}`);
|
|
return response.data;
|
|
},
|
|
|
|
searchCardsByName: async (cardName: string, game?: string) => {
|
|
const response = await api.get(`/cards/search/name/${cardName}`, {
|
|
params: game ? { game } : {}
|
|
});
|
|
return response.data;
|
|
},
|
|
|
|
getSets: async (game: string) => {
|
|
const response = await api.get(`/cards/sets/${game}`);
|
|
return response.data;
|
|
},
|
|
};
|
|
|
|
export const collectionService = {
|
|
getMyCollections: async () => {
|
|
const response = await api.get('/collections/');
|
|
return response.data;
|
|
},
|
|
|
|
getCollection: async (collectionId: number) => {
|
|
const response = await api.get(`/collections/${collectionId}`);
|
|
return response.data;
|
|
},
|
|
|
|
getCollectionCards: async (collectionId: number) => {
|
|
const response = await api.get(`/collections/${collectionId}/cards`);
|
|
return response.data;
|
|
},
|
|
};
|
|
|
|
export const deckService = {
|
|
getMyDecks: async () => {
|
|
const response = await api.get('/decks/');
|
|
return response.data;
|
|
},
|
|
|
|
getDeck: async (deckId: number) => {
|
|
const response = await api.get(`/decks/${deckId}`);
|
|
return response.data;
|
|
},
|
|
|
|
getDeckCards: async (deckId: number) => {
|
|
const response = await api.get(`/decks/${deckId}/cards`);
|
|
return response.data;
|
|
},
|
|
};
|
|
|
|
export const authService = {
|
|
login: async (username: string, password: string) => {
|
|
const formData = new FormData();
|
|
formData.append('username', username);
|
|
formData.append('password', password);
|
|
|
|
const response = await api.post('/auth/token', formData, {
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
});
|
|
return response.data;
|
|
},
|
|
|
|
register: async (userData: any) => {
|
|
const response = await api.post('/auth/register', userData);
|
|
return response.data;
|
|
},
|
|
|
|
getCurrentUser: async () => {
|
|
const response = await api.get('/auth/me');
|
|
return response.data;
|
|
},
|
|
};
|
|
|
|
export default api;
|