From 8559b615734760ff060ac2c714c8fca80d5ed251 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Mon, 30 Jun 2025 00:59:25 -0700 Subject: add score import page --- frontend/src/pages/Import.tsx | 266 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) (limited to 'frontend/src/pages/Import.tsx') diff --git a/frontend/src/pages/Import.tsx b/frontend/src/pages/Import.tsx index e69de29..877e0e4 100644 --- a/frontend/src/pages/Import.tsx +++ b/frontend/src/pages/Import.tsx @@ -0,0 +1,266 @@ +import { useState, useEffect } from 'react'; +import { Link, useNavigate } from 'react-router'; +import { useAuth } from '../contexts/AuthContext'; +import JsonUploadModal from '../components/modals/JsonUploadModal'; + +interface SupportedGame { + internalName: string; + formattedName: string; + description: string; +} + +const Import = () => { + const { user, isLoading, logout } = useAuth(); + const navigate = useNavigate(); + const [selectedGame, setSelectedGame] = useState(''); + const [isJsonModalOpen, setIsJsonModalOpen] = useState(false); + const [supportedGames, setSupportedGames] = useState([]); + const [gamesLoading, setGamesLoading] = useState(true); + const [uploadStatus, setUploadStatus] = useState<{ + type: 'success' | 'error' | null; + message: string; + }>({ type: null, message: '' }); + + useEffect(() => { + const fetchSupportedGames = async () => { + try { + const response = await fetch(import.meta.env.VITE_API_URL+'/supportedGames'); + if (!response.ok) { + throw new Error('Failed to fetch supported games'); + } + const data = await response.json(); + setSupportedGames(data); + } catch (error) { + console.error('Failed to fetch supported games:', error); + setUploadStatus({ + type: 'error', + message: 'Failed to load supported games. Please refresh the page.' + }); + } finally { + setGamesLoading(false); + } + }; + + fetchSupportedGames(); + }, []); + + const handleLogout = async () => { + try { + await logout(); + navigate('/'); + } catch (error) { + console.error('Logout failed:', error); + alert('Network error during logout. Please try again.'); + } + }; + + const handleJsonUpload = async (data: any) => { + try { + console.log('Uploading data for game:', selectedGame, data); + const response = await fetch(`${import.meta.env.VITE_API_URL}/uploadScore`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify({ + meta: { + game: data.meta.game, + service: data.meta.service, + playtype: data.meta.playtype + }, + scores: data.scores + }) + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.error || 'Failed to upload scores'); + } + + const result = await response.json(); + + setUploadStatus({ + type: 'success', + message: `Successfully imported ${result.scoreCount} score(s) for ${supportedGames.find(g => g.internalName === data.meta.game)?.formattedName || data.meta.game}` + }); + + setTimeout(() => { + setUploadStatus({ type: null, message: '' }); + }, 5000); + } catch (error) { + console.error('Upload failed:', error); + setUploadStatus({ + type: 'error', + message: error instanceof Error ? error.message : 'Failed to import data. Please try again.' + }); + } + }; + + if (isLoading) { + return ( +
+
+
+

Loading import page...

+
+
+ ); + } + + if (!user) { + return ( +
+
+
+

Session Expired

+

Please sign in to import your data.

+
+ + Sign In + + + Back to Home + +
+
+
+
+ ); + } + + return ( +
+ {/* Navigation */} + + + {/* Main Content */} +
+ {/* Header */} +
+

Import Data

+

Import your game scores and progress from various sources

+
+ + {/* Status Message */} + {uploadStatus.type && ( +
+

+ {uploadStatus.message} +

+
+ )} + + {/* Game Selection Card */} +
+
+

Select Game

+

+ Choose the game you want to import data for +

+ + {gamesLoading ? ( +
+
+
+ Loading games... +
+
+ ) : ( + + )} +
+ + {/* Import Options */} + {selectedGame && ( +
+

Import Options

+ +
+ {/* JSON Upload Card */} +
+
+ + + +
+

Batch-Manual Upload

+

+ Upload your game data from a Mirage compatible JSON file +

+ +
+
+
+ )} +
+
+ + {/* JSON Upload Modal */} + setIsJsonModalOpen(false)} + onUpload={handleJsonUpload} + game={supportedGames.find(g => g.internalName === selectedGame)?.formattedName || ''} + /> +
+ ); +}; + +export default Import; -- cgit v1.2.3