<div class="profile-picture profile-picture--without-image">
<div class="profile-picture__inner">
<div class="profile-picture__visual" data-default="/graphics/combine-with-mobile.jpg"></div>
<a href="#" class="profile-picture__btn profile-picture__btn--delete">
<div class="profile-picture__btn__icon"><svg class="icon-delete" viewBox="0 0 24 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 3.60416H23" stroke="currentColor" stroke-width="1.55" stroke-linecap="round" />
<path d="M9.38097 1H14.6191" stroke="currentColor" stroke-width="1.55" stroke-linecap="round" />
<path d="M3.61904 6.20834L5.3354 22.4211C5.55081 24.4559 7.26705 26 9.31317 26H14.7802C16.7865 26 18.4824 24.5137 18.7456 22.5248L20.9048 6.20834" stroke="currentColor" stroke-width="1.55" stroke-linecap="round" />
<path d="M7.80952 7.77084L8.85714 22.3542" stroke="currentColor" stroke-width="1.55" stroke-linecap="round" />
<path d="M12 7.77084V22.3542" stroke="currentColor" stroke-width="1.55" stroke-linecap="round" />
<path d="M15.1429 22.3542L16.1905 7.77084" stroke="currentColor" stroke-width="1.55" stroke-linecap="round" />
</svg>
</div>
</a>
<form class="profile-picture__form" method="" action="#" enctype="multipart/form-data">
<label class="profile-picture__btn profile-picture__btn--edit">
<input type="file" name="_profilePhoto" class="profile-picture__file hidden" accept="image/png, image/jpeg" />
<div class="profile-picture__btn__icon profile-picture__btn__icon--edit"><svg viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.1031 7.77778H4.73333C2.67147 7.77778 1 9.44925 1 11.5111V31.2667C1 33.3285 2.67147 35 4.73333 35H24.4889C26.5508 35 28.2222 33.3285 28.2222 31.2667V17.5778" stroke="currentColor" stroke-width="1.55" stroke-linecap="round" />
<path d="M32.8444 3.15563C33.9819 4.29312 33.9819 6.13735 32.8444 7.27484L18.6282 21.491C18.5957 21.5235 18.5546 21.5458 18.5097 21.5552L13.7156 22.5645C13.5485 22.5997 13.4003 22.4515 13.4355 22.2844L14.4448 17.4903C14.4542 17.4454 14.4765 17.4043 14.509 17.3718L28.7252 3.15563C29.8627 2.01814 31.7069 2.01814 32.8444 3.15563Z" stroke="currentColor" stroke-width="1.55" />
<path d="M28.25 4.83334L31.1667 7.75" stroke="currentColor" stroke-width="1.55" stroke-linecap="round" />
</svg>
</div>
</label>
</form>
</div>
<div class="profile-picture__messages">
<div class="profile-picture__message profile-picture__message--success hidden">Picture is updated.</div>
<div class="profile-picture__message profile-picture__message--error hidden">Could not update picture!</div>
</div>
</div>
<div class="profile-picture profile-picture--without-image">
<div class="profile-picture__inner">
<div class="profile-picture__visual" data-default="/graphics/combine-with-mobile.jpg"></div>
<a href="#" class="profile-picture__btn profile-picture__btn--delete">
<div class="profile-picture__btn__icon">{{render "@icon-delete"}}</div>
</a>
<form class="profile-picture__form" method="" action="#" enctype="multipart/form-data">
<label class="profile-picture__btn profile-picture__btn--edit">
<input type="file" name="_profilePhoto" class="profile-picture__file hidden" accept="image/png, image/jpeg" />
<div class="profile-picture__btn__icon profile-picture__btn__icon--edit">{{render "@icon-edit"}}</div>
</label>
</form>
</div>
<div class="profile-picture__messages">
<div class="profile-picture__message profile-picture__message--success hidden">Picture is updated.</div>
<div class="profile-picture__message profile-picture__message--error hidden">Could not update picture!</div>
</div>
</div>
/* No context defined. */
.profile-picture {
$pictureSizeMobile: 100px;
$pictureSize: 150px;
$iconSize: 20px;
display: flex;
justify-content: flex-start;
align-items: center;
&__inner {
flex: 0 0 auto;
position: relative;
width: $pictureSize;
height: $pictureSize;
}
&__messages {
flex: 0 1 auto;
display: none;
margin: 0;
padding: 0 0 0 var(--gap--4);
&--show {
display: block;
}
}
&__message--error {
color: var(--color--negative);
}
&__visual {
position: relative;
z-index: 1;
width: $pictureSize;
height: $pictureSize;
border-radius: $pictureSize;
border: 1px solid var(--color--neutrals-3);
overflow: hidden;
background-position: 50% 50%;
background-size: contain;
background-color: var(--color--neutrals-1);
background-repeat: no-repeat;
}
&__btn {
position: absolute;
top: 1px;
right: 1px;
bottom: 1px;
left: 1px;
z-index: 2;
display: none;
justify-content: center;
align-items: center;
color: var(--color-neutrals-1);
border-radius: $pictureSize;
overflow: hidden;
opacity: 0;
cursor: pointer;
&__icon {
flex: 0 0 $iconSize;
width: $iconSize;
height: $iconSize;
&--edit {
$iconCleanMove: round($iconSize / 6);
transform: translate($iconCleanMove, 0);
}
}
}
&.profile-picture--with-image .profile-picture__btn--delete,
&.profile-picture--without-image .profile-picture__btn--edit {
display: flex;
}
&.profile-picture--without-image .profile-picture__btn--edit:hover,
&.profile-picture--with-image .profile-picture__btn--delete:hover {
color: var(--color-neutrals-10);
background-color: rgba(255, 255, 255, .8);
backdrop-filter: blur(1px);
opacity: 1;
}
@media screen and (max-width: 640px) {
&__inner,
&__visual {
width: $pictureSizeMobile;
height: $pictureSizeMobile;
}
}
}
const PROFILEPICTURE = ((w, d, undefined) => {
"use strict";
const selectors = {
wrapper: '.profile-picture',
visual: '.profile-picture__visual',
file: '.profile-picture__file',
delete: '.profile-picture__btn--delete',
form: '.profile-picture__form',
messages: '.profile-picture__messages',
successMessage: '.profile-picture__message--success',
errorMessage: '.profile-picture__message--error',
};
const classes = {
withImage: 'profile-picture--with-image',
withoutImage: 'profile-picture--without-image',
showMessages: 'profile-picture__messages--show',
hidden: 'hidden',
};
const messageSeconds = 4000;
let defaultPhoto;
const init = () => {
[...d.querySelectorAll(selectors.wrapper), ...[]].forEach(wrapper => {
const visual = wrapper.querySelector(selectors.visual);
const file = wrapper.querySelector(selectors.file);
const form = wrapper.querySelector(selectors.form);
const messages = wrapper.querySelector(selectors.messages);
const successMessage = wrapper.querySelector(selectors.successMessage);
const errorMessage = wrapper.querySelector(selectors.errorMessage);
if (!visual || !file || !form) {
return;
}
defaultPhoto = visual.dataset.default;
window.gigya.accounts.getAccountInfo({
callback: d => {
let picture = (d && d.profile && d.profile.photoURL && d.profile.photoURL.length) ? d.profile.photoURL : defaultPhoto;
updateVisual(wrapper, visual, picture);
},
});
file.addEventListener('change', e => {
if (file.files && file.files.length) {
const fileReader = new FileReader();
fileReader.readAsDataURL(file.files[0]);
fileReader.onload = data => {
const photoBytes = data.target.result.split(',')[1];
window.gigya.accounts.setProfilePhoto({
publish: true,
photoBytes: photoBytes,
APIKey: window.gigya.apiKey,
callback: r => {
if (r.errorMessage === 'OK') {
window.gigya.accounts.getAccountInfo({
callback: d => {
if (d && d.profile && d.profile.photoURL && d.profile.photoURL.length) {
updateVisual(wrapper, visual, d.profile.photoURL);
showMessage(messages, successMessage, errorMessage, !!d.profile.photoURL.length);
}
},
});
}
},
});
};
}
});
const del = wrapper.querySelector(selectors.delete);
if (del) {
del.addEventListener('click', e => {
e.preventDefault();
setDefaultPhoto(wrapper, visual, file);
});
}
});
};
const setDefaultPhoto = async function(wrapper, visual, file) {
let blob = await fetch(defaultPhoto)
.then(r => r.blob())
.catch(e => console.log('Fetch error:', e));
let dataUrl = await new Promise(resolve => {
let reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
dataUrl = dataUrl.split(',')[1] ?? dataUrl.split(';')[1] ?? dataUrl;
window.gigya.accounts.setProfilePhoto({
publish: true,
photoBytes: dataUrl,
APIKey: window.gigya.apiKey,
callback: setProfileResponse => {
if (setProfileResponse.errorMessage === 'OK') {
window.gigya.accounts.getAccountInfo({
callback: getAccountResponse => {
if (getAccountResponse && getAccountResponse.profile && getAccountResponse.profile.photoURL) {
clearVisual(wrapper, visual, file, getAccountResponse.profile.photoURL);
}
},
});
}
},
});
};
const updateVisual = (wrapper, visual, url) => {
if (!wrapper || !visual || !url) {
throw new Error('Could not update profile picture visual.');
}
wrapper.classList.remove(classes.withoutImage);
wrapper.classList.add(classes.withImage);
visual.style.backgroundImage = "url('" + url + "')";
};
const clearVisual = (wrapper, visual, file, url) => {
if (!wrapper || !visual || !file || !url) {
throw new Error('Could not clear profile picture visual.');
}
wrapper.classList.remove(classes.withImage);
wrapper.classList.add(classes.withoutImage);
visual.style.backgroundImage = "url('" + url + "')";
file.value = '';
};
let timeout = 0;
const showMessage = (wrapper, successMessageItem, errorMessageItem, success) => {
if (!wrapper || !successMessageItem || !errorMessageItem) {
return;
}
const showItem = !!success ? successMessageItem : errorMessageItem;
showItem.classList.remove(classes.hidden);
wrapper.classList.add(classes.showMessages);
clearTimeout(timeout || 0);
timeout = setTimeout(() => {
wrapper.classList.remove(classes.showMessages);
successMessageItem.classList.add(classes.hidden);
errorMessageItem.classList.add(classes.hidden);
}, messageSeconds);
};
d.addEventListener('DOMContentLoaded', init);
})(window, window.document);
No notes defined.