const Component = use('util.Component'); export default def(class CodeEntryView extends Component { static ID = 'ui.component.CodeEntryView'; static PROPERTIES = { value: {}, error: {}, is_checking_code: {}, } static RENDER_MODE = Component.NO_SHADOW; static CSS = /*css*/` .wrapper { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #3e5362; } fieldset[name=number-code] { display: flex; justify-content: space-between; gap: 5px; } .digit-input { box-sizing: border-box; flex-grow: 1; height: 50px; font-size: 25px; text-align: center; border-radius: 0.5rem; -moz-appearance: textfield; border: 2px solid #9b9b9b; color: #485660; } .digit-input::-webkit-outer-spin-button, .digit-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } .confirm-code-hyphen { display: inline-block; flex-grow: 2; text-align: center; font-size: 40px; font-weight: 300; } ` create_template ({ template }) { // TODO: static member for strings const submit_btn_txt = i18n('confirm_code_generic_submit'); $(template).html(/*html*/`
-
`); } on_focus () { $(this.dom_).find('.digit-input').first().focus(); } on_ready ({ listen }) { listen('error', (error) => { if ( ! error ) return $(this.dom_).find('.error').hide(); $(this.dom_).find('.error').text(error).show(); }); listen('value', value => { // clear the inputs if ( value === undefined ) { $(this.dom_).find('.digit-input').val(''); return; } }) listen('is_checking_code', (is_checking_code, { old_value }) => { if ( old_value === is_checking_code ) return; if ( old_value === undefined ) return; const $button = $(this.dom_).find('.code-confirm-btn'); if ( is_checking_code ) { // set animation $button.prop('disabled', true); $button.html(`circle anim`); return; } const submit_btn_txt = i18n('confirm_code_generic_try_again'); $button.html(submit_btn_txt); $button.prop('disabled', false); }); const that = this; $(this.dom_).find('.code-confirm-btn').on('click submit', function(e){ e.preventDefault(); e.stopPropagation(); const $button = $(this); $button.prop('disabled', true); $button.closest('.error').hide(); that.set('is_checking_code', true); // force update to trigger the listener that.set('value', that.get('value')); }) // Elements const numberCodeForm = this.dom_.querySelector('[data-number-code-form]'); const numberCodeInputs = [...numberCodeForm.querySelectorAll('[data-number-code-input]')]; // Event listeners numberCodeForm.addEventListener('input', ({ target }) => { const inputLength = target.value.length || 0; let currentIndex = Number(target.dataset.numberCodeInput); if(inputLength === 2){ const inputValues = target.value.split(''); target.value = inputValues[0]; } else if (inputLength > 1) { const inputValues = target.value.split(''); inputValues.forEach((value, valueIndex) => { const nextValueIndex = currentIndex + valueIndex; if (nextValueIndex >= numberCodeInputs.length) { return; } numberCodeInputs[nextValueIndex].value = value; }); currentIndex += inputValues.length - 2; } const nextIndex = currentIndex + 1; if (nextIndex < numberCodeInputs.length) { numberCodeInputs[nextIndex].focus(); } // Concatenate all inputs into one string to create the final code let current_code = ''; for(let i=0; i< numberCodeInputs.length; i++){ current_code += numberCodeInputs[i].value; } const submit_btn_txt = i18n('confirm_code_generic_submit'); $(this.dom_).find('.code-confirm-btn').html(submit_btn_txt); // Automatically submit if 6 digits entered if(current_code.length === 6){ $(this.dom_).find('.code-confirm-btn').prop('disabled', false); this.set('value', current_code); this.set('is_checking_code', true); } else { $(this.dom_).find('.code-confirm-btn').prop('disabled', true); } }); numberCodeForm.addEventListener('keydown', (e) => { const { code, target } = e; const currentIndex = Number(target.dataset.numberCodeInput); const previousIndex = currentIndex - 1; const nextIndex = currentIndex + 1; const hasPreviousIndex = previousIndex >= 0; const hasNextIndex = nextIndex <= numberCodeInputs.length - 1 switch (code) { case 'ArrowLeft': case 'ArrowUp': if (hasPreviousIndex) { numberCodeInputs[previousIndex].focus(); } e.preventDefault(); break; case 'ArrowRight': case 'ArrowDown': if (hasNextIndex) { numberCodeInputs[nextIndex].focus(); } e.preventDefault(); break; case 'Backspace': if (!e.target.value.length && hasPreviousIndex) { numberCodeInputs[previousIndex].value = null; numberCodeInputs[previousIndex].focus(); } break; default: break; } }); } })