|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function initializeStepper() {
|
|
|
updateStepperUI();
|
|
|
attachStepperEventListeners();
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function goToStep(stepNumber) {
|
|
|
if (stepNumber < 1 || stepNumber > totalSteps) return;
|
|
|
|
|
|
currentStep = stepNumber;
|
|
|
updateStepperUI();
|
|
|
scrollToTop();
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function nextStep() {
|
|
|
if (currentStep < totalSteps) {
|
|
|
currentStep++;
|
|
|
updateStepperUI();
|
|
|
scrollToTop();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function prevStep() {
|
|
|
if (currentStep > 1) {
|
|
|
currentStep--;
|
|
|
updateStepperUI();
|
|
|
scrollToTop();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function markStepCompleted(stepNumber) {
|
|
|
const step = document.querySelector(`.step[data-step="${stepNumber}"]`);
|
|
|
if (step) {
|
|
|
step.classList.add('completed');
|
|
|
}
|
|
|
|
|
|
|
|
|
const stepLines = document.querySelectorAll('.step-line');
|
|
|
if (stepLines[stepNumber - 1]) {
|
|
|
stepLines[stepNumber - 1].classList.add('completed');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function updateStepperUI() {
|
|
|
|
|
|
document.querySelectorAll('.step').forEach((step, index) => {
|
|
|
const stepNum = index + 1;
|
|
|
step.classList.remove('active');
|
|
|
|
|
|
if (stepNum === currentStep) {
|
|
|
step.classList.add('active');
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
document.querySelectorAll('.step-content').forEach((content, index) => {
|
|
|
const stepNum = index + 1;
|
|
|
content.classList.remove('active');
|
|
|
|
|
|
if (stepNum === currentStep) {
|
|
|
content.classList.add('active');
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function resetStepper() {
|
|
|
currentStep = 1;
|
|
|
|
|
|
|
|
|
document.querySelectorAll('.step').forEach(step => {
|
|
|
step.classList.remove('completed', 'active');
|
|
|
});
|
|
|
|
|
|
document.querySelectorAll('.step-line').forEach(line => {
|
|
|
line.classList.remove('completed');
|
|
|
});
|
|
|
|
|
|
updateStepperUI();
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function getCurrentStep() {
|
|
|
return currentStep;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function scrollToTop() {
|
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function attachStepperEventListeners() {
|
|
|
|
|
|
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();
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
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();
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
const prevStep3 = document.getElementById('prevStep3');
|
|
|
if (prevStep3) {
|
|
|
prevStep3.addEventListener('click', () => goToStep(2));
|
|
|
}
|
|
|
|
|
|
const analyzeAnother = document.getElementById('analyzeAnother');
|
|
|
if (analyzeAnother) {
|
|
|
analyzeAnother.addEventListener('click', async () => {
|
|
|
|
|
|
await handleSaveAndReset();
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function initializeStep2() {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
import('./workflow.js').then(module => {
|
|
|
module.showEmbryoImageAndDetect();
|
|
|
});
|
|
|
}, 150);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function initializeStep3() {
|
|
|
|
|
|
import('./workflow.js').then(module => {
|
|
|
module.evaluateAllEmbryos();
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function resetWorkflow() {
|
|
|
|
|
|
const imageInput = document.getElementById('imageInput');
|
|
|
if (imageInput) {
|
|
|
imageInput.value = '';
|
|
|
}
|
|
|
|
|
|
|
|
|
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';
|
|
|
}
|
|
|
|
|
|
|
|
|
const nextStep1 = document.getElementById('nextStep1');
|
|
|
if (nextStep1) nextStep1.disabled = true;
|
|
|
|
|
|
const nextStep2 = document.getElementById('nextStep2');
|
|
|
if (nextStep2) nextStep2.disabled = true;
|
|
|
|
|
|
|
|
|
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>
|
|
|
`;
|
|
|
}
|
|
|
|
|
|
|
|
|
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>';
|
|
|
}
|
|
|
|
|
|
|
|
|
const embryoThumbnails = document.getElementById('embryoThumbnails');
|
|
|
if (embryoThumbnails) {
|
|
|
embryoThumbnails.innerHTML = '';
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
const cropControls = document.getElementById('cropControls');
|
|
|
const editCropBtn = document.getElementById('editCropBtn');
|
|
|
if (cropControls) cropControls.style.display = 'none';
|
|
|
if (editCropBtn) editCropBtn.style.display = 'none';
|
|
|
|
|
|
|
|
|
import('../state.js').then(module => {
|
|
|
module.appState.croppedEmbryos = [];
|
|
|
module.appState.embryoResults = [];
|
|
|
module.appState.embryoRemarks = {};
|
|
|
module.appState.currentEmbryoIndex = 0;
|
|
|
module.appState.currentImage = null;
|
|
|
module.appState.zoomLevel = 1;
|
|
|
module.appState.finalResult = null;
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function enableNextButton(stepNumber) {
|
|
|
const button = document.getElementById(`nextStep${stepNumber}`);
|
|
|
if (button) {
|
|
|
button.disabled = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function disableNextButton(stepNumber) {
|
|
|
const button = document.getElementById(`nextStep${stepNumber}`);
|
|
|
if (button) {
|
|
|
button.disabled = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 {
|
|
|
|
|
|
const embryoData = prepareEmbryoData(
|
|
|
appState.croppedEmbryos,
|
|
|
appState.currentImage,
|
|
|
appState.embryoResults,
|
|
|
appState.embryoRemarks
|
|
|
);
|
|
|
|
|
|
|
|
|
const docId = await saveGradingResults(embryoData);
|
|
|
|
|
|
|
|
|
console.log('Results saved successfully! Document ID:', docId);
|
|
|
return true;
|
|
|
} catch (error) {
|
|
|
console.error('Error saving results:', error);
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function handleSaveAndReset() {
|
|
|
|
|
|
await handleSaveResults();
|
|
|
|
|
|
|
|
|
resetStepper();
|
|
|
resetWorkflow();
|
|
|
}
|
|
|
|