({
...c,
id: this.base64UrlToBuffer(c.id),
})),
};
const assertion = await navigator.credentials.get({ publicKey });
const body = {
id: assertion.id,
rawId: this.bufferToBase64Url(assertion.rawId),
type: assertion.type,
response: {
authenticatorData: this.bufferToBase64Url(assertion.response.authenticatorData),
clientDataJSON: this.bufferToBase64Url(assertion.response.clientDataJSON),
signature: this.bufferToBase64Url(assertion.response.signature),
userHandle: assertion.response.userHandle ? this.bufferToBase64Url(assertion.response.userHandle) : null,
},
};
const authResp = await fetch('https://newbutchery.nl/checkout/passkey/auth/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const result = await authResp.json();
if (result.error) {
throw new Error(result.message);
}
window.location.href = 'https://newbutchery.nl/customer/account/';
} catch (error) {
if (error.name === 'NotAllowedError') {
// User cancelled
} else {
this.errorMessage = error.message || "Inloggen met passkey mislukt.";
}
} finally {
this.passkeyLoading = false;
}
},
async sendLoginCode() {
this.codeSending = true;
this.codeError = '';
try {
const formKey = typeof hyva !== 'undefined' ? hyva.getFormKey() : (document.querySelector('input[name=form_key]')?.value || '');
const response = await fetch('https://newbutchery.nl/checkout/login/sendLoginCode/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
form_key: formKey,
email: this.email
})
});
const data = await response.json();
if (data.success) {
this.codeSent = true;
this.codeDigits = ['', '', '', '', '', ''];
this.loginCode = '';
this.$nextTick(() => {
const firstInput = this.$refs.codeInput0;
if (firstInput) firstInput.focus();
});
} else {
this.codeError = data.message || "Er is een fout opgetreden.";
}
} catch (error) {
this.codeError = "Er is een fout opgetreden. Probeer het opnieuw.";
} finally {
this.codeSending = false;
}
},
handleCodeInput(index, event) {
const value = event.target.value.replace(/\D/g, '');
if (value.length > 1) {
for (let i = 0; i < 6; i++) {
this.codeDigits[i] = value[i] || '';
const input = this.$refs['codeInput' + i];
if (input) input.value = this.codeDigits[i];
}
const lastIndex = Math.min(value.length, 6) - 1;
const lastInput = this.$refs['codeInput' + lastIndex];
if (lastInput) lastInput.focus();
} else {
this.codeDigits[index] = value.charAt(0) || '';
event.target.value = this.codeDigits[index];
if (value && index < 5) {
const next = this.$refs['codeInput' + (index + 1)];
if (next) next.focus();
}
}
this.loginCode = this.codeDigits.join('');
if (this.loginCode.length === 6) {
this.verifyLoginCode();
}
},
handleCodeKeydown(index, event) {
if (event.key === 'Backspace' && !this.codeDigits[index] && index > 0) {
const prev = this.$refs['codeInput' + (index - 1)];
if (prev) {
this.codeDigits[index - 1] = '';
prev.value = '';
prev.focus();
}
}
},
handleCodePaste(event) {
event.preventDefault();
const pasted = (event.clipboardData || window.clipboardData).getData('text').replace(/\D/g, '').substring(0, 6);
for (let i = 0; i < 6; i++) {
this.codeDigits[i] = pasted[i] || '';
const input = this.$refs['codeInput' + i];
if (input) input.value = this.codeDigits[i];
}
this.loginCode = this.codeDigits.join('');
if (pasted.length > 0) {
const lastIndex = Math.min(pasted.length, 6) - 1;
const lastInput = this.$refs['codeInput' + lastIndex];
if (lastInput) lastInput.focus();
}
if (this.loginCode.length === 6) {
this.verifyLoginCode();
}
},
async verifyLoginCode() {
this.codeVerifying = true;
this.codeError = '';
try {
const formKey = typeof hyva !== 'undefined' ? hyva.getFormKey() : (document.querySelector('input[name=form_key]')?.value || '');
const response = await fetch('https://newbutchery.nl/checkout/login/verifyLoginCode/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
form_key: formKey,
code: this.loginCode
})
});
const data = await response.json();
if (data.success) {
window.location.href = 'https://newbutchery.nl/customer/account/';
} else {
this.codeError = data.message || "De inlogcode is onjuist.";
if (data.code_expired) {
this.codeSent = false;
this.loginCode = '';
this.codeDigits = ['', '', '', '', '', ''];
} else {
this.codeDigits = ['', '', '', '', '', ''];
this.loginCode = '';
this.$nextTick(() => {
const firstInput = this.$refs.codeInput0;
if (firstInput) firstInput.focus();
});
}
}
} catch (error) {
this.codeError = "Er is een fout opgetreden. Probeer het opnieuw.";
} finally {
this.codeVerifying = false;
}
},
changeEmail() {
this.emailChecked = false;
this.emailExists = false;
this.password = '';
this.errorMessage = '';
this.loginSuccess = false;
this.failedAttempts = 0;
this.codeSent = false;
this.codeError = '';
this.loginCode = '';
this.codeDigits = ['', '', '', '', '', ''];
this.$nextTick(() => {
this.$refs.emailInput?.focus();
});
},
validateEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
},
base64UrlToBuffer(base64url) {
const base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');
const pad = base64.length % 4;
const padded = pad ? base64 + '='.repeat(4 - pad) : base64;
const binary = atob(padded);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes.buffer;
},
bufferToBase64Url(buffer) {
const bytes = new Uint8Array(buffer);
let binary = '';
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
}">