Spaces:
Running
Running
| import { completedIcon, pendingIcon, processingIcon } from './constants.js'; | |
| import { apiBaseUrl, clientId, estTimeStep1, estTimeStep2 } from './main.js'; | |
| import { t, onLanguageChange } from './i18n.js'; | |
| const statusFaceCheckElement = document.getElementById('status-face-check'); | |
| const baseServices = [ | |
| { | |
| id: 1, | |
| name: 'Geolocation', | |
| displayKey: 'serviceGeolocation', | |
| }, | |
| { | |
| id: 2, | |
| name: 'Timestamp', | |
| displayKey: 'serviceTimestamp', | |
| }, | |
| { | |
| id: 3, | |
| name: 'AIGVDetection', | |
| displayKey: 'serviceAIGVDetection', | |
| }, | |
| { | |
| id: 4, | |
| name: 'Report', | |
| displayKey: 'serviceReport', | |
| }, | |
| ]; | |
| const createInitData = () => | |
| baseServices.map((service) => ({ | |
| ...service, | |
| status: 'pending', | |
| percent: 0, | |
| })); | |
| export let statusStep1 = 'pending'; | |
| export let statusStep2 = 'pending'; | |
| let _estTimeStep1 = 0; | |
| let _estTimeStep2 = 0; | |
| function formatText(key, params = {}) { | |
| let value = t(key) || ''; | |
| Object.entries(params).forEach(([k, v]) => { | |
| value = value.replace(`{${k}}`, v); | |
| }); | |
| return value; | |
| } | |
| function getDisplayName(item) { | |
| if (item.displayKey) { | |
| const translated = t(item.displayKey); | |
| if (translated) return translated; | |
| } | |
| return item.displayName || item.name || ''; | |
| } | |
| function renderStatus(newValue, countItem, countItemCompleted) { | |
| const percent = Math.round((countItemCompleted / countItem) * 100); | |
| const step1Message = | |
| statusStep1 === 'pending' | |
| ? `${t('waitingLabel')} - ${ | |
| _estTimeStep1 === 0 | |
| ? t('calculatingLabel') | |
| : formatText('minutesRemaining', { minutes: _estTimeStep1 }) | |
| }` | |
| : statusStep1 === 'processing' | |
| ? formatText('processingEstimate', { minutes: _estTimeStep1 }) | |
| : t('completedLabel'); | |
| const step2Message = | |
| statusStep2 === 'pending' | |
| ? `${t('waitingLabel')} - ${ | |
| _estTimeStep2 === 0 | |
| ? t('calculatingLabel') | |
| : formatText('beginsAfterStep1', { minutes: _estTimeStep2 }) | |
| }` | |
| : statusStep2 === 'processing' | |
| ? formatText('processingEstimate', { minutes: _estTimeStep2 }) | |
| : t('completedLabel'); | |
| return `<div class="status-face-check"> | |
| <div class="header-status-face-check"> | |
| <div class="title-status-face-check"> | |
| <p>${formatText('statusHeaderCompleted', { | |
| completed: countItemCompleted, | |
| total: countItem, | |
| })}</p> | |
| <p>${formatText('statusPercent', { percent })}</p> | |
| </div> | |
| <div class="wrapper-processing"> | |
| <div class="processing" style="width: ${percent}%;"></div> | |
| </div> | |
| </div> | |
| <div class="body-status-face-check"> | |
| ${newValue | |
| .map((item, index) => { | |
| return ` | |
| ${ | |
| index === 0 | |
| ? `<div class="step">${formatText('stepTitle', { | |
| step: 1, | |
| })} ${step1Message}</div>` | |
| : '' | |
| } | |
| ${ | |
| index === 3 | |
| ? `<div class="step">${formatText('stepTitle', { | |
| step: 2, | |
| })} ${step2Message} </div>` | |
| : '' | |
| } | |
| <div class="item-status-face-check"> | |
| <span | |
| >${ | |
| item.status === 'completed' | |
| ? completedIcon | |
| : item.status === 'processing' | |
| ? processingIcon | |
| : pendingIcon | |
| } | |
| </span> | |
| <div class="content-status-face-check"> | |
| <p class="name-service">${formatText('serviceLabel', { | |
| index: index + 1, | |
| total: countItem, | |
| name: getDisplayName(item), | |
| })}</p> | |
| <p class="status-service ${ | |
| item.status === 'pending' | |
| ? 'display-none' | |
| : item.status === 'processing' | |
| ? 'processing-dots' | |
| : '' | |
| }">${ | |
| item.status === 'processing' | |
| ? t('statusProcessing') | |
| : item.status === 'completed' | |
| ? t('statusCompleted') | |
| : t('statusPending') | |
| }<span class="dots "></span></p> | |
| </div> | |
| </div>`; | |
| }) | |
| .join('')} | |
| </div> | |
| </div>`; | |
| } | |
| let data = {}; | |
| Object.defineProperty(data, 'value', { | |
| set(newValue) { | |
| const countItem = newValue.length; | |
| const countItemCompleted = newValue.filter( | |
| (item) => item.status === 'completed' | |
| ).length; | |
| statusStep1 = 'pending'; | |
| statusStep2 = newValue.find((i) => i.name === 'Report').status; | |
| if ( | |
| ['Geolocation', 'Timestamp', 'AIGVDetection'].every((item) => { | |
| return newValue.find((i) => i.name === item).status === 'completed'; | |
| }) | |
| ) { | |
| statusStep1 = 'completed'; | |
| } else if ( | |
| ['Geolocation', 'Timestamp', 'AIGVDetection'].some((item) => { | |
| return newValue.find((i) => i.name === item).status === 'processing'; | |
| }) | |
| ) { | |
| statusStep1 = 'processing'; | |
| } | |
| const content = renderStatus(newValue, countItem, countItemCompleted); | |
| statusFaceCheckElement.innerHTML = content; | |
| this._value = newValue; | |
| }, | |
| get() { | |
| return this._value; | |
| }, | |
| }); | |
| data.value = createInitData(); | |
| onLanguageChange(() => { | |
| if (data.value) { | |
| data.value = data.value; | |
| } | |
| }); | |
| export function initValueData() { | |
| console.log('test...'); | |
| } | |
| let isLoading = {}; | |
| Object.defineProperty(isLoading, 'value', { | |
| set(newValue) { | |
| if (newValue) { | |
| // statusFaceCheckElement.classList.remove('display-none'); | |
| data.value = createInitData(); | |
| } else { | |
| statusFaceCheckElement.classList.add('display-none'); | |
| data.value = createInitData(); | |
| } | |
| this._value = newValue; | |
| }, | |
| get() { | |
| return this._value; | |
| }, | |
| }); | |
| const source = new EventSource(apiBaseUrl + `v1/sse?client_id=${clientId}`); | |
| source.onopen = () => console.log('✅ SSE connected'); | |
| let _interval; | |
| source.onmessage = (event) => { | |
| try { | |
| const _data = JSON.parse(event.data); | |
| console.log(_data); | |
| if (_data?.status) { | |
| if (_data.status === 'start') { | |
| isLoading.value = true; | |
| _estTimeStep1 = estTimeStep1; | |
| _estTimeStep2 = estTimeStep2; | |
| _interval = setInterval(() => { | |
| if (statusStep1 === 'processing' && _estTimeStep1 > 1) { | |
| _estTimeStep1 -= 1; | |
| } | |
| if (statusStep2 === 'processing' && _estTimeStep2 > 1) { | |
| _estTimeStep2 -= 1; | |
| } | |
| data.value = data.value; | |
| }, 60000); | |
| } else { | |
| setTimeout(() => { | |
| isLoading.value = false; | |
| _estTimeStep1 = 0; | |
| _estTimeStep2 = 0; | |
| data.value = createInitData(); | |
| clearInterval(_interval); | |
| }, 2500); | |
| } | |
| } | |
| if (_data?.status_service) { | |
| const updatedData = data.value?.map((item) => { | |
| if (_data.service === item.name) { | |
| if (_data.status_service === 'completed') { | |
| return { ...item, status: _data.status_service, percent: 100 }; | |
| } | |
| return { ...item, status: _data.status_service }; | |
| } | |
| return item; | |
| }); | |
| data.value = updatedData; | |
| } | |
| } catch (err) { | |
| console.log('err', err); | |
| } | |
| }; | |
| source.onerror = (err) => { | |
| console.error('❌ SSE error:', err); | |
| }; | |