import { Form, FormGroup, ActionGroup, FileUpload, Avatar, Button, HelperText, HelperTextItem } from "@patternfly/react-core"; import { useState, CSSProperties } from "react"; import { useTranslation } from "react-i18next"; import { useEnvironment } from "../root/KeycloakContext"; import { useAlerts, HelpItem } from "ui-shared"; interface AvatarFormProps { accountUrl: string; } interface AvatarFormState { errors: any; imageBlob: any; filename: string; avatarUrl: string; avatarSrc: string; noAvatarSrc: string; } export const AvatarForm = ({accountUrl} : AvatarFormProps) => { const { t } = useTranslation(); const context = useEnvironment(); const urlparts = accountUrl.indexOf('?') > 0 ? accountUrl.split('?') : accountUrl; const currentAvatarUrl = Array.isArray(urlparts) ? urlparts[0] + "-avatar?" + urlparts[1] : urlparts + "-avatar"; const noavatar = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjAuMiwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAzNiAzNiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzYgMzY7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7ZmlsbDojRjBGMEYwO30KCS5zdDF7ZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7ZmlsbDojRDJEMkQyO30KCS5zdDJ7ZmlsbDojQjhCQkJFO30KCS5zdDN7ZmlsbDojRDJEMkQyO30KPC9zdHlsZT4KPHJlY3QgY2xhc3M9InN0MCIgd2lkdGg9IjM2IiBoZWlnaHQ9IjM2Ii8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0xNy43LDIwLjFjLTMuNSwwLTYuNC0yLjktNi40LTYuNHMyLjktNi40LDYuNC02LjRzNi40LDIuOSw2LjQsNi40UzIxLjMsMjAuMSwxNy43LDIwLjF6Ii8+CjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMy4zLDM2bDAtNi43Yy0yLDAuNC0yLjksMS40LTMuMSwzLjVMMTAuMSwzNkgxMy4zeiIvPgo8cGF0aCBjbGFzcz0ic3QzIiBkPSJNMTAuMSwzNmwwLjEtMy4yYzAuMi0yLjEsMS4xLTMuMSwzLjEtMy41bDAsNi43aDkuNGwwLTYuN2MyLDAuNCwyLjksMS40LDMuMSwzLjVsMC4xLDMuMmg0LjcKCWMtMC40LTMuOS0xLjMtOS0yLjktMTFjLTEuMS0xLjQtMi4zLTIuMi0zLjUtMi42cy0xLjgtMC42LTYuMy0wLjZzLTYuMSwwLjctNi4xLDAuN2MtMS4yLDAuNC0yLjQsMS4yLTMuNCwyLjYKCUM2LjcsMjcsNS44LDMyLjIsNS40LDM2SDEwLjF6Ii8+CjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0yNS45LDM2bC0wLjEtMy4yYy0wLjItMi4xLTEuMS0zLjEtMy4xLTMuNWwwLDYuN0gyNS45eiIvPgo8L3N2Zz4="; const initialState = { errors: {avatar: ""}, imageBlob: null, filename: "", avatarUrl: currentAvatarUrl, avatarSrc: currentAvatarUrl, noAvatarSrc: noavatar }; const [state, setState] = useState(initialState); const { addAlert, addError } = useAlerts(); const reader = new FileReader(); let currentFilename = ""; reader.onloadend = (event: any) => { var imgData = String(event.target!.result) imageScale(imgData, (blob: Blob) => { setState({ errors: {avatar: ""}, imageBlob: blob, filename: currentFilename, avatarUrl: currentAvatarUrl, avatarSrc: URL.createObjectURL(blob), noAvatarSrc: noavatar }) }) }; const handleFileInputChange = (_: any, file: File) => { if (file != null && file.name != "") { if (file.type.startsWith("image")) { currentFilename = file.name; reader.readAsDataURL(file); } else { console.error("Wrong file type: " + file.type); } } }; const handleClear = (_: any) => { setState(initialState); }; const imageScale = (imgData: string, callback: any) => { var img = new Image() img.src = imgData img.onload = (event: Event) => { var canvas = document.createElement("canvas") var ctx = canvas.getContext("2d") ctx!.drawImage(img, 0, 0) var MAX_WIDTH = 250 var MAX_HEIGHT = 250 var width = img.width var height = img.height if (width > height) { if (width > MAX_WIDTH) { height *= MAX_WIDTH / width width = MAX_WIDTH } } else { if (height > MAX_HEIGHT) { width *= MAX_HEIGHT / height height = MAX_HEIGHT } } canvas.width = width canvas.height = height ctx = canvas.getContext("2d") ctx!.drawImage(img, 0, 0, width, height) canvas.toBlob(callback) } } const handleSubmit = (event: React.FormEvent): void => { event.preventDefault() const form = event.target as HTMLFormElement var formData = new FormData(form) formData.append("image", state.imageBlob) var xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => { if (xhr.readyState == 4) { if (200 <= xhr.status && xhr.status <= 204) { addAlert(t("avatarUpdatedMessage")); // force reload avatar setState(initialState); } else { addError(xhr.response); } } } xhr.open(form.method, form.action, true); xhr.send(formData); } const handleError = (event: any) => { setState({ errors: {avatar: t('error-noAvatarFound')}, imageBlob: null, filename: "", avatarUrl: "", avatarSrc: "", noAvatarSrc: noavatar }) }; const { filename, avatarUrl, avatarSrc, noAvatarSrc } = state; const avatarStyle = { objectFit: 'cover', width: '150px', height: '150px', border: '1px solid lightgray', boxShadow: 'lightgray 6px 3px 10px 2px' } as CSSProperties; return (
{state.errors.avatar !== "" && {state.errors.avatar} } { avatarSrc !== "" ? : } } >
) }; export default AvatarForm;