mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
rendering profile in sidebar
This commit is contained in:
parent
68c6acaf64
commit
1d3d1a44a8
@ -11,7 +11,7 @@ import (
|
||||
func GetProfileImage(w http.ResponseWriter, r *http.Request) {
|
||||
var data []byte
|
||||
|
||||
account, code, err := BearerAppToken(r, true);
|
||||
account, code, err := ParamAppToken(r, true);
|
||||
if err != nil {
|
||||
ErrResponse(w, code, err)
|
||||
return
|
||||
|
@ -77,6 +77,40 @@ func BearerAccountToken(r *http.Request) (*store.AccountToken, error) {
|
||||
return &accountToken, nil
|
||||
}
|
||||
|
||||
func ParamAppToken(r *http.Request, detail bool) (*store.Account, int, error) {
|
||||
|
||||
// parse authentication token
|
||||
target, access, err := ParseToken(r.FormValue("token"))
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
// find token record
|
||||
var app store.App
|
||||
if detail {
|
||||
if err := store.DB.Preload("Account.AccountDetail").Where("account_id = ? AND token = ?", target, access).First(&app).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, http.StatusNotFound, err
|
||||
} else {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := store.DB.Preload("Account").Where("account_id = ? AND token = ?", target, access).First(&app).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, http.StatusNotFound, err
|
||||
} else {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if app.Account.Disabled {
|
||||
return nil, http.StatusGone, errors.New("account is inactive")
|
||||
}
|
||||
|
||||
return &app.Account, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func BearerAppToken(r *http.Request, detail bool) (*store.Account, int, error) {
|
||||
|
||||
// parse bearer authentication
|
||||
|
@ -9,6 +9,7 @@ func getProfileModel(account *store.Account) *Profile {
|
||||
return &Profile{
|
||||
Guid: account.Guid,
|
||||
Handle: account.Username,
|
||||
Name: account.AccountDetail.Name,
|
||||
Description: account.AccountDetail.Description,
|
||||
Location: account.AccountDetail.Location,
|
||||
Image: account.AccountDetail.Image,
|
||||
|
@ -102,7 +102,7 @@ func TestProfileUpdate(t *testing.T) {
|
||||
APP_TOKENAPP, set.A.Token, &profile, nil))
|
||||
|
||||
// retrieve profile image
|
||||
data, hdr, err = ApiTestData(GetProfileImage, "GET", "/profile/image", nil, nil,
|
||||
data, hdr, err = ApiTestData(GetProfileImage, "GET", "/profile/image?token=" + set.A.Token, nil, nil,
|
||||
APP_TOKENAPP, set.A.Token, 0, 0)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
@ -7,6 +7,12 @@ export function Login(props) {
|
||||
|
||||
const { state, actions } = useLogin()
|
||||
|
||||
const keyDown = (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
actions.onLogin()
|
||||
}
|
||||
}
|
||||
|
||||
return(
|
||||
<LoginWrapper>
|
||||
<div class="container">
|
||||
@ -15,9 +21,9 @@ export function Login(props) {
|
||||
<span class="subheader-text">Communication for the Decentralized Web</span>
|
||||
</div>
|
||||
<LoginInput size="large" spellCheck="false" placeholder="username" prefix={<UserOutlined />}
|
||||
onChange={(e) => actions.setUsername(e.target.value)} value={state.username} />
|
||||
onChange={(e) => actions.setUsername(e.target.value)} value={state.username} onKeyDown={(e) => keyDown(e)}/>
|
||||
<LoginPassword size="large" spellCheck="false" placeholder="password" prefix={<LockOutlined />}
|
||||
onChange={(e) => actions.setPassword(e.target.value)} value={state.password} />
|
||||
onChange={(e) => actions.setPassword(e.target.value)} value={state.password} onKeyDown={(e) => keyDown(e)}/>
|
||||
<LoginEnter type="primary" onClick={() => actions.onLogin()} disabled={actions.isDisabled()}>
|
||||
<span>Sign In</span>
|
||||
</LoginEnter>
|
||||
|
@ -28,7 +28,7 @@ export function useLogin() {
|
||||
return false
|
||||
},
|
||||
onLogin: async () => {
|
||||
if (!state.spinning) {
|
||||
if (!state.spinning && state.username != '' && state.password != '') {
|
||||
actions.updateState({ spinning: true })
|
||||
try {
|
||||
await app.actions.login(state.username, state.password)
|
||||
|
48
net/web/src/User/SideBar/Identity/Identity.jsx
Normal file
48
net/web/src/User/SideBar/Identity/Identity.jsx
Normal file
@ -0,0 +1,48 @@
|
||||
import { Avatar, Image } from 'antd';
|
||||
import React from 'react'
|
||||
import { IdentityWrapper } from './Identity.styled';
|
||||
import { DownOutlined, EditOutlined, UserOutlined } from '@ant-design/icons';
|
||||
import { useIdentity } from './useIdentity.hook';
|
||||
import { Menu, Dropdown } from 'antd';
|
||||
|
||||
export function Identity() {
|
||||
|
||||
const { state, actions } = useIdentity()
|
||||
|
||||
const Logo = () => {
|
||||
if (state.imageUrl === '') {
|
||||
return <Avatar size={64} icon={<UserOutlined />} />
|
||||
}
|
||||
return <Avatar size={64} src={<Image preview={false} src={ state.imageUrl } style={{ width: 64 }} />} />
|
||||
}
|
||||
|
||||
const menu = (
|
||||
<Menu>
|
||||
<Menu.Item key="0">
|
||||
<div onClick={() => {}}>Edit Profile</div>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="1">
|
||||
<div onClick={() => actions.logout()}>Sign Out</div>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
return (
|
||||
<IdentityWrapper>
|
||||
<Dropdown overlay={menu} overlayStyle={{ minWidth: 0 }} trigger={['click']} placement="bottomRight">
|
||||
<div>
|
||||
<div class="container">
|
||||
<div class="logo">
|
||||
<Logo />
|
||||
</div>
|
||||
<div class="username">
|
||||
<span class="name">{ state.name }</span>
|
||||
<span class="handle">{ state.handle }</span>
|
||||
</div>
|
||||
<DownOutlined />
|
||||
</div>
|
||||
</div>
|
||||
</Dropdown>
|
||||
</IdentityWrapper>
|
||||
)
|
||||
}
|
68
net/web/src/User/SideBar/Identity/Identity.styled.js
Normal file
68
net/web/src/User/SideBar/Identity/Identity.styled.js
Normal file
@ -0,0 +1,68 @@
|
||||
import { Button } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const IdentityWrapper = styled.div`
|
||||
background-color: #f6f5ed;
|
||||
border-bottom: 2px solid #8fbea7;
|
||||
border-top: 1px solid #8fbea7;
|
||||
border-left: 0px;
|
||||
border-right: 0px;
|
||||
border-radius: 0px;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.menu {
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 33%
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.username {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.edit {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 1.25em;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.handle {
|
||||
font-size: 1em;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.domain {
|
||||
font-size: 1em;
|
||||
color: #444444;
|
||||
}
|
||||
`;
|
42
net/web/src/User/SideBar/Identity/useIdentity.hook.js
Normal file
42
net/web/src/User/SideBar/Identity/useIdentity.hook.js
Normal file
@ -0,0 +1,42 @@
|
||||
import { useContext, useState, useEffect } from 'react';
|
||||
import { AppContext } from '../../../AppContext/AppContext';
|
||||
|
||||
export function useIdentity() {
|
||||
|
||||
const [state, setState] = useState({
|
||||
name: '',
|
||||
handle: '',
|
||||
domain: '',
|
||||
imageUrl: ''
|
||||
});
|
||||
|
||||
const actions = {
|
||||
logout: async () => {
|
||||
app.actions.logout()
|
||||
}
|
||||
};
|
||||
|
||||
const app = useContext(AppContext);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (app?.state?.Data?.profile) {
|
||||
let profile = app.state.Data.profile;
|
||||
if (profile.name != null) {
|
||||
updateState({ name: profile.name });
|
||||
}
|
||||
if (profile.image != null) {
|
||||
updateState({ imageUrl: 'https://' + profile.node + '/profile/image?token=' + app.state.token })
|
||||
} else {
|
||||
updateState({ imageUrl: '' })
|
||||
}
|
||||
updateState({ handle: profile.handle });
|
||||
updateState({ domain: profile.node });
|
||||
}
|
||||
}, [app])
|
||||
|
||||
return { state, actions };
|
||||
}
|
12
net/web/src/User/SideBar/SideBar.jsx
Normal file
12
net/web/src/User/SideBar/SideBar.jsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react'
|
||||
import { SideBarWrapper } from './SideBar.styled';
|
||||
import { Identity } from './Identity/Identity';
|
||||
|
||||
export function SideBar() {
|
||||
|
||||
return (
|
||||
<SideBarWrapper>
|
||||
<Identity />
|
||||
</SideBarWrapper>
|
||||
)
|
||||
}
|
11
net/web/src/User/SideBar/SideBar.styled.js
Normal file
11
net/web/src/User/SideBar/SideBar.styled.js
Normal file
@ -0,0 +1,11 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const SideBarWrapper = styled.div`
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
max-width: 300px;
|
||||
min-width: 200px;
|
||||
border: 1px solid #8fbea7;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
@ -2,6 +2,7 @@ import React from 'react'
|
||||
import { useUser } from './useUser.hook';
|
||||
import { Button } from 'antd';
|
||||
import { UserWrapper } from './User.styled';
|
||||
import { SideBar } from './SideBar/SideBar';
|
||||
import connect from '../connect.png';
|
||||
|
||||
|
||||
@ -11,11 +12,10 @@ export function User() {
|
||||
|
||||
return (
|
||||
<UserWrapper>
|
||||
<div class="listing">
|
||||
<Button type="primary" onClick={() => actions.onLogout()} style={{ alignSelf: 'center', marginTop: '16px', width: '33%' }}>Sign Out</Button>
|
||||
</div>
|
||||
<SideBar />
|
||||
<div class="canvas">
|
||||
<img class="connect" src={connect} alt="" />
|
||||
<Button type="primary" onClick={() => actions.onLogout()} style={{ alignSelf: 'center', marginTop: '16px', width: '33%' }}>Sign Out</Button>
|
||||
</div>
|
||||
</UserWrapper>
|
||||
)
|
||||
|
@ -8,16 +8,9 @@ export const UserWrapper = styled.div`
|
||||
height: 100%;
|
||||
background-color: #f6f5ed;
|
||||
|
||||
.listing {
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
max-width: 300px;
|
||||
min-width: 200px;
|
||||
border: 1px solid #8fbea7;
|
||||
}
|
||||
|
||||
.canvas {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
border: 1px solid #8fbea7;
|
||||
|
@ -9,8 +9,6 @@ export function useUser() {
|
||||
const navigate = useNavigate();
|
||||
const app = useContext(AppContext);
|
||||
|
||||
console.log(app);
|
||||
|
||||
const actions = {
|
||||
onLogout: async () => {
|
||||
app.actions.logout()
|
||||
|
Loading…
Reference in New Issue
Block a user