diff --git a/net/web/package.json b/net/web/package.json
index 2600e485..45b580ab 100644
--- a/net/web/package.json
+++ b/net/web/package.json
@@ -10,6 +10,7 @@
"base-64": "^1.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
+ "react-easy-crop": "^4.1.4",
"react-router-dom": "^6.2.2",
"react-scripts": "5.0.0",
"styled-components": "^5.3.3",
diff --git a/net/web/src/User/Profile/Profile.jsx b/net/web/src/User/Profile/Profile.jsx
index e9883f58..2415084d 100644
--- a/net/web/src/User/Profile/Profile.jsx
+++ b/net/web/src/User/Profile/Profile.jsx
@@ -1,20 +1,24 @@
-import React, { useState, useEffect } from 'react'
-import { ProfileWrapper, CloseButton } from './Profile.styled';
+import React, { useState, useEffect, useRef } from 'react'
+import { ProfileWrapper, CloseButton, ModalFooter, SelectButton } from './Profile.styled';
import { UserOutlined, CloseOutlined, EditOutlined } from '@ant-design/icons';
import { useProfile } from './useProfile.hook';
import { Button, Modal } from 'antd'
import { ProfileInfo } from './ProfileInfo/ProfileInfo';
+import { ProfileImage } from './ProfileImage/ProfileImage';
export function Profile(props) {
+ const [ logoVisible, setLogoVisible ] = useState(false);
const [ infoVisible, setInfoVisible ] = useState(false);
const { state, actions } = useProfile();
+ const imageFile = useRef(null)
const Logo = () => {
if (state.imageUrl != null) {
if (state.imageUrl === '') {
return
}
+ return
}
return <>>
}
@@ -46,6 +50,29 @@ export function Profile(props) {
}
}
+ const onSelectImage = () => {
+ imageFile.current.click();
+ };
+
+ const selected = (e) => {
+ var reader = new FileReader();
+ reader.onload = () => {
+ actions.setModalImage(reader.result);
+ }
+ reader.readAsDataURL(e.target.files[0]);
+ }
+
+ const Footer = (
+
+ selected(e)} style={{display: 'none'}}/>
+
+
+
+
+
+
+ );
+
return (
-
-
![]({)
+
setLogoVisible(true)}>
+
@@ -66,16 +93,13 @@ export function Profile(props) {
-
onProfileSave()}
- onCancel={() => setInfoVisible(false)}
- >
+ 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 dd4e5662..c2fd62e0 100644
--- a/net/web/src/User/Profile/Profile.styled.js
+++ b/net/web/src/User/Profile/Profile.styled.js
@@ -102,6 +102,16 @@ export const ProfileWrapper = styled.div`
}
`;
+export const ModalFooter = styled.div`
+ width: 100%;
+ display: flex;
+
+ .select {
+ display: flex;
+ flex-grow: 1;
+ }
+`
+
export const CloseButton = styled(Button)`
font-size: 24px;
color: #aaaaaa;
diff --git a/net/web/src/User/Profile/ProfileImage/ProfileImage.jsx b/net/web/src/User/Profile/ProfileImage/ProfileImage.jsx
new file mode 100644
index 00000000..4eaa604a
--- /dev/null
+++ b/net/web/src/User/Profile/ProfileImage/ProfileImage.jsx
@@ -0,0 +1,33 @@
+import React, { useState } from 'react';
+import Cropper from 'react-easy-crop'
+import { UserOutlined } from '@ant-design/icons';
+import { 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 = (croppedArea, croppedAreaPixels) => {
+ console.log("crop complete");
+ };
+
+ const Logo = () => {
+ if (state.modalImage == null) {
+ return
+ }
+ return <>>
+ }
+
+ const onSelect = () => {
+ console.log("ON SELECT");
+ }
+
+ return (
+
+ onSelect()} image={state.modalImage} crop={crop} zoom={zoom} aspect={1}
+ onCropChange={setCrop} onCropComplete={onCropComplete} onZoomChange={setZoom} />
+
+
+ )
+}
diff --git a/net/web/src/User/Profile/ProfileImage/ProfileImage.styled.js b/net/web/src/User/Profile/ProfileImage/ProfileImage.styled.js
new file mode 100644
index 00000000..416a02a0
--- /dev/null
+++ b/net/web/src/User/Profile/ProfileImage/ProfileImage.styled.js
@@ -0,0 +1,25 @@
+import styled from 'styled-components';
+
+export const ProfileImageWrapper = styled.div`
+ position: relative;
+ height: 200px;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+`;
+
+export const ProfileDefaultImage = styled.div`
+ width: 192px;
+ height: 192px;
+ border: 1px solid #dddddd;
+ border-radius: 8px;
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ position: absolute;
+ color: #888888;
+ font-size: 6em;
+ cursor: pointer;
+`;
+
diff --git a/net/web/src/User/Profile/useProfile.hook.js b/net/web/src/User/Profile/useProfile.hook.js
index 400e9f4c..b99a501c 100644
--- a/net/web/src/User/Profile/useProfile.hook.js
+++ b/net/web/src/User/Profile/useProfile.hook.js
@@ -14,6 +14,7 @@ export function useProfile() {
modalName: '',
modalLocation: '',
modalDescription: '',
+ modalImage: null,
});
const navigate = useNavigate();
@@ -36,6 +37,9 @@ export function useProfile() {
setModalDescription: (value) => {
updateState({ modalDescription: value });
},
+ setModalImage: (value) => {
+ updateState({ modalImage: value });
+ },
setModalProfile: async () => {
let set = false
if(!state.modalBusy) {
@@ -58,8 +62,10 @@ export function useProfile() {
let profile = app.state.Data.profile;
if (profile.image != null) {
updateState({ imageUrl: app.actions.profileImageUrl() })
+ updateState({ modalImage: app.actions.profileImageUrl() })
} else {
updateState({ imageUrl: '' })
+ updateState({ modalImage: null })
}
updateState({ name: profile.name });
updateState({ modalName: profile.name });
diff --git a/net/web/yarn.lock b/net/web/yarn.lock
index cc6add26..9483ef5c 100644
--- a/net/web/yarn.lock
+++ b/net/web/yarn.lock
@@ -6187,6 +6187,11 @@ normalize-url@^6.0.1:
resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
+normalize-wheel@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45"
+ integrity sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=
+
npm-run-path@^4.0.1:
version "4.0.1"
resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz"
@@ -7630,6 +7635,14 @@ react-dom@^17.0.2:
object-assign "^4.1.1"
scheduler "^0.20.2"
+react-easy-crop@^4.1.4:
+ version "4.1.4"
+ resolved "https://registry.yarnpkg.com/react-easy-crop/-/react-easy-crop-4.1.4.tgz#71543f7156f038b37bc45c4b7eb141173e623d38"
+ integrity sha512-Gw07jxdeJAGQAFybyNa2HYzviNjNJ3lyNTEApbA0zHcZ9N8f77iH3w1dEB5PbxbrG+LXvxFmMPNgMBoDpz27tQ==
+ dependencies:
+ normalize-wheel "^1.0.1"
+ tslib "2.0.1"
+
react-error-overlay@^6.0.10:
version "6.0.10"
resolved "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz"
@@ -8738,6 +8751,11 @@ tsconfig-paths@^3.12.0:
minimist "^1.2.0"
strip-bom "^3.0.0"
+tslib@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e"
+ integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==
+
tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"