Embryo-One's picture
Upload 49 files
ed9f15f verified
/**
* Stepper Navigation - Handles multi-step workflow
*/
import { showConfirmModal } from './modal.js';
import { saveGradingResults, prepareEmbryoData, isFirebaseReady } from '../utils/firebaseService.js';
import { appState } from '../state.js';
import { showToast } from './toast.js';
let currentStep = 1;
const totalSteps = 3;
/**
* Initialize stepper navigation
*/
export function initializeStepper() {
updateStepperUI();
attachStepperEventListeners();
}
/**
* Navigate to a specific step
*/
export function goToStep(stepNumber) {
if (stepNumber < 1 || stepNumber > totalSteps) return;
currentStep = stepNumber;
updateStepperUI();
scrollToTop();
}
/**
* Go to next step
*/
export function nextStep() {
if (currentStep < totalSteps) {
currentStep++;
updateStepperUI();
scrollToTop();
}
}
/**
* Go to previous step
*/
export function prevStep() {
if (currentStep > 1) {
currentStep--;
updateStepperUI();
scrollToTop();
}
}
/**
* Mark a step as completed
*/
export function markStepCompleted(stepNumber) {
const step = document.querySelector(`.step[data-step="${stepNumber}"]`);
if (step) {
step.classList.add('completed');
}
// Update step line
const stepLines = document.querySelectorAll('.step-line');
if (stepLines[stepNumber - 1]) {
stepLines[stepNumber - 1].classList.add('completed');
}
}
/**
* Update stepper UI
*/
function updateStepperUI() {
// Update step indicators
document.querySelectorAll('.step').forEach((step, index) => {
const stepNum = index + 1;
step.classList.remove('active');
if (stepNum === currentStep) {
step.classList.add('active');
}
});
// Update step content visibility
document.querySelectorAll('.step-content').forEach((content, index) => {
const stepNum = index + 1;
content.classList.remove('active');
if (stepNum === currentStep) {
content.classList.add('active');
}
});
}
/**
* Reset stepper to first step
*/
export function resetStepper() {
currentStep = 1;
// Remove completed status from all steps
document.querySelectorAll('.step').forEach(step => {
step.classList.remove('completed', 'active');
});
document.querySelectorAll('.step-line').forEach(line => {
line.classList.remove('completed');
});
updateStepperUI();
}
/**
* Get current step number
*/
export function getCurrentStep() {
return currentStep;
}
/**
* Scroll to top of page
*/
function scrollToTop() {
window.scrollTo({ top: 0, behavior: 'smooth' });
}
/**
* Attach event listeners for step navigation
*/
function attachStepperEventListeners() {
// Step 1 navigation
const nextStep1 = document.getElementById('nextStep1');
if (nextStep1) {
nextStep1.addEventListener('click', () => {
markStepCompleted(1);
goToStep(2);
initializeStep2();
});
}
const startOverBtn = document.getElementById('startOverBtn');
if (startOverBtn) {
startOverBtn.addEventListener('click', async () => {
const confirmed = await showConfirmModal(
'Are you sure you want to start over? All progress will be lost.',
'Start Over'
);
if (confirmed) {
resetStepper();
resetWorkflow();
}
});
}
// Step 2 navigation
const prevStep2 = document.getElementById('prevStep2');
if (prevStep2) {
prevStep2.addEventListener('click', () => goToStep(1));
}
const nextStep2 = document.getElementById('nextStep2');
if (nextStep2) {
nextStep2.addEventListener('click', () => {
markStepCompleted(2);
goToStep(3);
initializeStep3();
});
}
// Step 3 navigation
const prevStep3 = document.getElementById('prevStep3');
if (prevStep3) {
prevStep3.addEventListener('click', () => goToStep(2));
}
const analyzeAnother = document.getElementById('analyzeAnother');
if (analyzeAnother) {
analyzeAnother.addEventListener('click', async () => {
// Save results first, then reset
await handleSaveAndReset();
});
}
}
/**
* Initialize Step 2 - Show embryo image and prepare for detection
*/
function initializeStep2() {
// Show the embryo image first, then trigger detection after UI is ready
setTimeout(() => {
import('./workflow.js').then(module => {
module.showEmbryoImageAndDetect();
});
}, 150);
}
/**
* Initialize Step 3 - Evaluate all embryos in background
*/
function initializeStep3() {
// Trigger evaluation of all embryos in background
import('./workflow.js').then(module => {
module.evaluateAllEmbryos();
});
}
/**
* Reset workflow (to be called from workflow.js)
*/
export function resetWorkflow() {
// Reset file input to allow re-uploading the same file
const imageInput = document.getElementById('imageInput');
if (imageInput) {
imageInput.value = '';
}
// Clear images
const mainImage = document.getElementById('mainImage');
const mainImagePreview = document.getElementById('mainImagePreview');
const croppedImage = document.getElementById('croppedImage');
const cropCanvas = document.getElementById('cropCanvas');
if (mainImage) {
mainImage.style.display = 'none';
mainImage.src = '';
}
if (croppedImage) {
croppedImage.style.display = 'none';
croppedImage.src = '';
}
if (cropCanvas) {
cropCanvas.style.display = 'none';
}
if (mainImagePreview) {
const placeholder = mainImagePreview.querySelector('.placeholder');
if (placeholder) placeholder.style.display = 'flex';
}
// Reset buttons
const nextStep1 = document.getElementById('nextStep1');
if (nextStep1) nextStep1.disabled = true;
const nextStep2 = document.getElementById('nextStep2');
if (nextStep2) nextStep2.disabled = true;
// Clear classification status
const classificationStatus = document.getElementById('classificationStatus');
if (classificationStatus) {
classificationStatus.innerHTML = `
<p>Upload an image to check if it contains an embryo.</p>
<p>The system will automatically classify the image upon upload.</p>
`;
}
// Clear results
const finalResults = document.getElementById('finalResults');
if (finalResults) finalResults.innerHTML = '<p>Processing all embryos...</p>';
const finalPredictions = document.getElementById('finalPredictions');
if (finalPredictions) finalPredictions.innerHTML = '';
const selectionInfo = document.getElementById('selectionInfo');
if (selectionInfo) {
selectionInfo.innerHTML = '<p>Select an embryo to continue.</p>';
}
// Clear embryo thumbnails
const embryoThumbnails = document.getElementById('embryoThumbnails');
if (embryoThumbnails) {
embryoThumbnails.innerHTML = '';
}
// Disable zoom controls
const zoomIn = document.getElementById('zoomIn');
const zoomOut = document.getElementById('zoomOut');
const zoomReset = document.getElementById('zoomReset');
if (zoomIn) zoomIn.disabled = true;
if (zoomOut) zoomOut.disabled = true;
if (zoomReset) zoomReset.disabled = true;
// Hide crop editor
const cropControls = document.getElementById('cropControls');
const editCropBtn = document.getElementById('editCropBtn');
if (cropControls) cropControls.style.display = 'none';
if (editCropBtn) editCropBtn.style.display = 'none';
// Reset appState
import('../state.js').then(module => {
module.appState.croppedEmbryos = [];
module.appState.embryoResults = [];
module.appState.embryoRemarks = {}; // Clear all remarks
module.appState.currentEmbryoIndex = 0;
module.appState.currentImage = null;
module.appState.zoomLevel = 1;
module.appState.finalResult = null;
});
}
/**
* Enable next button for a step
*/
export function enableNextButton(stepNumber) {
const button = document.getElementById(`nextStep${stepNumber}`);
if (button) {
button.disabled = false;
}
}
/**
* Disable next button for a step
*/
export function disableNextButton(stepNumber) {
const button = document.getElementById(`nextStep${stepNumber}`);
if (button) {
button.disabled = true;
}
}
/**
* Handle saving results to Firebase
*/
async function handleSaveResults() {
if (!isFirebaseReady()) {
console.warn('Firebase is not configured.');
return false;
}
if (!appState.croppedEmbryos || appState.croppedEmbryos.length === 0) {
console.warn('No embryos to save');
return false;
}
try {
// Prepare the data with results and remarks
const embryoData = prepareEmbryoData(
appState.croppedEmbryos,
appState.currentImage,
appState.embryoResults,
appState.embryoRemarks
);
// Save to Firebase silently
const docId = await saveGradingResults(embryoData);
// Log to console for debugging
console.log('Results saved successfully! Document ID:', docId);
return true;
} catch (error) {
console.error('Error saving results:', error);
return false;
}
}
/**
* Handle saving results and then resetting for a new analysis
*/
async function handleSaveAndReset() {
// Save silently in background
await handleSaveResults();
// Reset immediately
resetStepper();
resetWorkflow();
}