diff --git a/net/web/src/AppContext/fetchUtil.js b/net/web/src/AppContext/fetchUtil.js
index d7afd771..2266d1ab 100644
--- a/net/web/src/AppContext/fetchUtil.js
+++ b/net/web/src/AppContext/fetchUtil.js
@@ -8,8 +8,8 @@ function checkResponse(response) {
}
}
-export function getProfileImageUrl(token) {
- return '/profile/image?agent=' + token
+export function getProfileImageUrl(token, revision) {
+ return '/profile/image?agent=' + token + "&revision=" + revision
}
async function fetchWithTimeout(url, options) {
@@ -61,6 +61,12 @@ export async function setProfileData(token, name, location, description) {
return await profile.json()
}
+export async function setProfileImage(token, image) {
+ let profile = await fetchWithTimeout('/profile/image?agent=' + token, { method: 'PUT', body: JSON.stringify(image), timeout: FETCH_TIMEOUT });
+ checkResponse(profile)
+ return await profile.json()
+}
+
export async function getGroups(token, revision) {
let param = "?agent=" + token
if (revision != null) {
diff --git a/net/web/src/AppContext/useAppContext.hook.js b/net/web/src/AppContext/useAppContext.hook.js
index 90bcdd76..73c46c58 100644
--- a/net/web/src/AppContext/useAppContext.hook.js
+++ b/net/web/src/AppContext/useAppContext.hook.js
@@ -1,5 +1,5 @@
import { useEffect, useState, useRef } from 'react';
-import { setProfileData, getProfileImageUrl, getProfile, getGroups, getAvailable, getUsername, setLogin, createAccount } from './fetchUtil';
+import { setProfileImage, setProfileData, getProfileImageUrl, getProfile, getGroups, getAvailable, getUsername, setLogin, createAccount } from './fetchUtil';
async function updateProfile(token, updateData) {
let profile = await getProfile(token);
@@ -71,10 +71,13 @@ export function useAppContext() {
appLogout(updateState, clearWebsocket);
resetData();
},
- setProfile: async (name, location, description) => {
+ setProfileData: async (name, location, description) => {
await setProfileData(state.token, name, location, description);
},
- profileImageUrl: () => getProfileImageUrl(state.token)
+ setProfileImage: async (image) => {
+ await setProfileImage(state.token, image);
+ },
+ profileImageUrl: () => getProfileImageUrl(state.token, state.Data?.profile?.revision)
}
const adminActions = {
diff --git a/net/web/src/User/Profile/Profile.jsx b/net/web/src/User/Profile/Profile.jsx
index a2a8c61e..ca9e9186 100644
--- a/net/web/src/User/Profile/Profile.jsx
+++ b/net/web/src/User/Profile/Profile.jsx
@@ -45,11 +45,17 @@ export function Profile(props) {
}
const onProfileSave = async () => {
- if (await actions.setModalProfile()) {
+ if (await actions.setProfileData()) {
setInfoVisible(false);
}
}
+ const onImageSave = async () => {
+ if (await actions.setProfileImage()) {
+ setLogoVisible(false);
+ }
+ }
+
const onSelectImage = () => {
imageFile.current.click();
};
@@ -64,12 +70,12 @@ export function Profile(props) {
const Footer = (
- selected(e)} style={{display: 'none'}}/>
+ selected(e)} style={{display: 'none'}}/>
-
+
);
@@ -88,7 +94,7 @@ export function Profile(props) {
setInfoVisible(true)}>
- detail:
+ details:
@@ -99,7 +105,7 @@ export function Profile(props) {
- onProfileSave()} onCancel={() => setInfoVisible(false)}>
diff --git a/net/web/src/User/Profile/Profile.styled.js b/net/web/src/User/Profile/Profile.styled.js
index 9f7e1a6e..2a26544d 100644
--- a/net/web/src/User/Profile/Profile.styled.js
+++ b/net/web/src/User/Profile/Profile.styled.js
@@ -84,6 +84,10 @@ export const ProfileWrapper = styled.div`
position: absolute;
padding-right: 8px;
cursor: pointer;
+ background: #f6f5ed;
+ padding-left: 8px;
+ border-radius: 4px;
+ border: 1px solid #dddddd;
}
.detailedit {
@@ -98,7 +102,7 @@ export const ProfileWrapper = styled.div`
.label {
padding-right: 8px;
- font-size: 1.2em;
+ font-size: 1em;
font-weight: bold;
color: #888888;
}
diff --git a/net/web/src/User/Profile/ProfileImage/ProfileImage.jsx b/net/web/src/User/Profile/ProfileImage/ProfileImage.jsx
index 99337443..1e0bcd43 100644
--- a/net/web/src/User/Profile/ProfileImage/ProfileImage.jsx
+++ b/net/web/src/User/Profile/ProfileImage/ProfileImage.jsx
@@ -1,15 +1,15 @@
import React, { useState, useCallback } from 'react';
import Cropper from 'react-easy-crop'
import { UserOutlined } from '@ant-design/icons';
-import { ProfileImageWrapper, ProfileDefaultImage } from './ProfileImage.styled';
+import { ProfileSpin, ProfileImageWrapper, ProfileDefaultImage } from './ProfileImage.styled';
export function ProfileImage({ state, actions }) {
const [crop, setCrop] = useState({ x: 0, y: 0 })
const [zoom, setZoom] = useState(1)
- const onCropComplete = useCallback((croppedArea, croppedAreaPixels) => {
- console.log("crop complete");
+ const onCropComplete = useCallback((area, crop) => {
+ actions.setModalCrop(crop.width, crop.height, crop.x, crop.y)
});
const Logo = () => {
@@ -19,15 +19,12 @@ export function ProfileImage({ state, actions }) {
return <>>
}
- const onSelect = () => {
- console.log("ON SELECT");
- }
-
return (
- onSelect()} image={state.modalImage} crop={crop} zoom={zoom} aspect={1}
+
+
)
}
diff --git a/net/web/src/User/Profile/ProfileImage/ProfileImage.styled.js b/net/web/src/User/Profile/ProfileImage/ProfileImage.styled.js
index 416a02a0..046a154d 100644
--- a/net/web/src/User/Profile/ProfileImage/ProfileImage.styled.js
+++ b/net/web/src/User/Profile/ProfileImage/ProfileImage.styled.js
@@ -1,3 +1,4 @@
+import { Spin } from 'antd';
import styled from 'styled-components';
export const ProfileImageWrapper = styled.div`
@@ -23,3 +24,8 @@ export const ProfileDefaultImage = styled.div`
cursor: pointer;
`;
+export const ProfileSpin = styled(Spin)`
+ position: absolute;
+ x-index: 10;
+`;
+
diff --git a/net/web/src/User/Profile/useProfile.hook.js b/net/web/src/User/Profile/useProfile.hook.js
index b99a501c..5ca62637 100644
--- a/net/web/src/User/Profile/useProfile.hook.js
+++ b/net/web/src/User/Profile/useProfile.hook.js
@@ -15,6 +15,7 @@ export function useProfile() {
modalLocation: '',
modalDescription: '',
modalImage: null,
+ crop: { w :0, h: 0, x: 0, y: 0 }
});
const navigate = useNavigate();
@@ -40,12 +41,15 @@ export function useProfile() {
setModalImage: (value) => {
updateState({ modalImage: value });
},
- setModalProfile: async () => {
+ setModalCrop: (w, h, x, y) => {
+ updateState({ crop: { w: w, h: h, x: x, y: y } });
+ },
+ setProfileData: async () => {
let set = false
if(!state.modalBusy) {
updateState({ modalBusy: true });
try {
- await app.actions.setProfile(state.modalName, state.modalLocation, state.modalDescription);
+ await app.actions.setProfileData(state.modalName, state.modalLocation, state.modalDescription);
set = true
}
catch (err) {
@@ -55,6 +59,39 @@ export function useProfile() {
}
return set
},
+ setProfileImage: async () => {
+ let set = false
+ if(!state.modalBusy) {
+ updateState({ modalBusy: true });
+ try {
+ const processImg = () => {
+ return new Promise((resolve, reject) => {
+ let img = new Image();
+ img.onload = () => {
+ var canvas = document.createElement("canvas");
+ var context = canvas.getContext('2d');
+ canvas.width = state.crop.w;
+ canvas.height = state.crop.h;
+ context.drawImage(img, state.crop.x, state.crop.y, state.crop.w, state.crop.h,
+ 0, 0, state.crop.w, state.crop.h);
+ resolve(canvas.toDataURL());
+ }
+ img.onerror = reject;
+ img.src = state.modalImage;
+ });
+ };
+ let dataUrl = await processImg();
+ let data = dataUrl.split(",")[1];
+ await app.actions.setProfileImage(data);
+ set = true
+ }
+ catch (err) {
+ window.alert(err);
+ }
+ updateState({ modalBusy: false });
+ }
+ return set;
+ },
};
useEffect(() => {
diff --git a/net/web/src/User/SideBar/Identity/Identity.jsx b/net/web/src/User/SideBar/Identity/Identity.jsx
index 14831b9a..bf1abd3c 100644
--- a/net/web/src/User/SideBar/Identity/Identity.jsx
+++ b/net/web/src/User/SideBar/Identity/Identity.jsx
@@ -10,6 +10,7 @@ export function Identity() {
const { state, actions } = useIdentity()
const Logo = () => {
+console.log(state);
if (state.imageUrl != null) {
if (state.imageUrl === '') {
return