adding profile image selector

This commit is contained in:
Roland Osborne 2022-03-23 14:28:07 -07:00
parent 65914d9189
commit 3fdc53715a
7 changed files with 129 additions and 12 deletions

View File

@ -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",

View File

@ -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 <div class="logo"><UserOutlined /></div>
}
return <img class="logo" src={ state.imageUrl } alt="" />
}
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 = (
<ModalFooter>
<input type='file' id='file' ref={imageFile} onChange={e => selected(e)} style={{display: 'none'}}/>
<div class="select">
<Button key="select" class="select" onClick={() => onSelectImage()}>Select Image</Button>
</div>
<Button key="select" onClick={() => setLogoVisible(false)}>Cancel</Button>
<Button key="save" type="primary" onClick={() => setLogoVisible(false)}>Save</Button>
</ModalFooter>
);
return (
<ProfileWrapper>
<div class="header">
@ -53,8 +80,8 @@ export function Profile(props) {
<CloseButton type="text" class="close" size={'large'} onClick={() => actions.close()} icon={<CloseOutlined />} />
</div>
<div class="profile">
<div class="avatar">
<img class="logo" src={ state.imageUrl } alt="" />
<div class="avatar" onClick={() => setLogoVisible(true)}>
<Logo />
<div class="logoedit">
<EditOutlined />
</div>
@ -66,16 +93,13 @@ export function Profile(props) {
<Button type="text" onClick={() => setInfoVisible(true)} icon={<EditOutlined />} />
</div>
</div>
<Modal
title="Profile Info"
centered
visible={infoVisible}
okText="Save"
onOk={() => onProfileSave()}
onCancel={() => setInfoVisible(false)}
>
<Modal title="Profile Info" centered visible={infoVisible} okText="Save"
onOk={() => onProfileSave()} onCancel={() => setInfoVisible(false)}>
<ProfileInfo state={state} actions={actions} />
</Modal>
<Modal title="Profile Image" centered visible={logoVisible} footer={Footer}>
<ProfileImage state={state} actions={actions} />
</Modal>
</ProfileWrapper>
)
}

View File

@ -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;

View File

@ -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 <ProfileDefaultImage class="logo"><UserOutlined /></ProfileDefaultImage>
}
return <></>
}
const onSelect = () => {
console.log("ON SELECT");
}
return (
<ProfileImageWrapper>
<Cropper onClick={() => onSelect()} image={state.modalImage} crop={crop} zoom={zoom} aspect={1}
onCropChange={setCrop} onCropComplete={onCropComplete} onZoomChange={setZoom} />
<Logo />
</ProfileImageWrapper>
)
}

View File

@ -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;
`;

View File

@ -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 });

View File

@ -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"