Files
julius_baer_onboarding/frontend/src/js/main.js
2025-04-12 23:23:11 +02:00

209 lines
7.7 KiB
JavaScript

// Import our custom CSS
import '../scss/styles.scss'
// Import all of Bootstrap's JS
import * as bootstrap from 'bootstrap'
import Alpine from 'alpinejs'
window.Alpine = Alpine
// Define an Alpine component to manage the game state
Alpine.data('gameManager', () => ({
// --- Component State ---
isLoading: false,
error: null,
gameData: null,
// --- Document State (add properties for each document type) ---
passportSrc: null, // For PNG data URL
accountSrc: null, // For PDF data URL
profileSrc: null, // For DOCX data URL (download link)
descriptionText: null, // For decoded TXT content
init() {
console.log('Game manager initializing...');
this.startNewGame();
},
// --- Helper Function to Process Document Data ---
processClientData(clientData) {
if (!clientData) {
console.log('No client data to process.');
this.passportSrc = null;
this.accountSrc = null;
this.profileSrc = null;
this.descriptionText = null;
return;
}
console.log('Processing client data for documents:', clientData);
// --- Passport (PNG) ---
if (clientData.passport) {
this.passportSrc = `data:image/png;base64,${clientData.passport}`;
} else {
this.passportSrc = null; // Reset if not provided
console.log('Passport base64 data not found.');
}
// --- Account (PDF) ---
if (clientData.account) {
this.accountSrc = `data:application/pdf;base64,${clientData.account}`;
} else {
this.accountSrc = null; // Reset if not provided
console.log('Account base64 data not found.');
}
// --- Profile (DOCX) - Create download link ---
if (clientData.profile) {
this.profileSrc = `data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,${clientData.profile}`;
} else {
this.profileSrc = null; // Reset if not provided
console.log('Profile base64 data not found.');
}
// --- Description (TXT) - Decode base64 ---
if (clientData.description) {
try {
this.descriptionText = atob(clientData.description);
} catch (e) {
console.error('Error decoding description base64:', e);
this.descriptionText = 'Error decoding document content.';
}
} else {
this.descriptionText = null; // Reset if not provided
console.log('Description base64 data not found.');
}
},
startNewGame() {
this.isLoading = true;
this.error = null;
this.gameData = null;
// Reset document states
this.processClientData(null);
// Use the browser's fetch API
fetch('http://127.0.0.1:5000/new-game', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
})
.then(response => {
if (!response.ok) {
return response.json().then(errData => {
throw new Error(errData.detail || `HTTP error! status: ${response.status}`);
}).catch(() => {
throw new Error(`HTTP error! status: ${response.status}`);
});
}
return response.json();
})
.then(data => {
console.log('New game data received:', data);
this.gameData = data;
// Process documents from the new game data
this.processClientData(this.gameData.client_data);
})
.catch(error => {
console.error('Error starting new game:', error);
this.error = error.message || 'Failed to start game. Check console/backend.';
})
.finally(() => {
this.isLoading = false;
});
},
submitDecision(decision) {
if (!decision || (decision !== 'Accept' && decision !== 'Reject')) {
this.error = 'Invalid decision provided.';
console.error('Invalid decision:', decision);
return;
}
if (!this.gameData || !this.gameData.session_id || !this.gameData.client_id) {
this.error = 'Missing game data (session or client ID). Cannot submit decision.';
console.error('Missing game data for decision:', this.gameData);
return;
}
if (this.isLoading) {
console.warn('Already processing a request.');
return;
}
if (this.gameData.status === 'gameover') {
console.warn('Game is already over.');
return;
}
console.log(`Submitting decision: ${decision} for client: ${this.gameData.client_id}`);
this.isLoading = true;
this.error = null;
// Reset document states before fetching new data
this.processClientData(null);
const requestBody = {
decision: decision,
session_id: this.gameData.session_id,
client_id: this.gameData.client_id
};
fetch('http://127.0.0.1:5000/next', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestBody)
})
.then(response => {
if (!response.ok) {
return response.text().then(text => {
try {
const errData = JSON.parse(text);
throw new Error(errData.detail || `HTTP error! status: ${response.status}`);
} catch (e) {
throw new Error(text || `HTTP error! status: ${response.status}`);
}
});
}
return response.json();
})
.then(data => {
console.log('Decision response received:', data);
// Update core game data
this.gameData.score = data.score;
this.gameData.status = data.status;
this.gameData.decision = data.decision;
this.gameData.bot_reason = data.bot_reason;
// Update client_id and client_data only if present and game not over
if (data.status !== 'gameover') {
if (data.client_id) {
this.gameData.client_id = data.client_id;
} else {
console.warn("Game continues but no new client ID received from /next endpoint.");
}
if (data.client_data) {
this.gameData.client_data = data.client_data;
// Process documents from the new client data
this.processClientData(this.gameData.client_data);
} else {
console.warn("Game continues but no new client data received from /next endpoint.");
this.gameData.client_data = null; // Clear old client data if none received
this.processClientData(null); // Ensure docs are cleared
}
} else {
console.log('Game Over! Final score:', this.gameData.score);
// Optionally clear client_id and client_data on gameover
// this.gameData.client_id = null;
// this.gameData.client_data = null;
// this.processClientData(null); // Clear docs on game over
}
})
.catch(error => {
console.error('Error submitting decision:', error);
this.error = error.message || 'Failed to submit decision.';
})
.finally(() => {
this.isLoading = false;
});
}
}));
Alpine.start()