rendering card sidebar

This commit is contained in:
Roland Osborne 2022-04-03 14:26:04 -07:00
parent f8824c6afe
commit 3276764f70
8 changed files with 191 additions and 55 deletions

View File

@ -14,7 +14,7 @@ import (
func GetCardProfileImage(w http.ResponseWriter, r *http.Request) {
var data []byte
account, code, err := BearerAppToken(r, false);
account, code, err := ParamAgentToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return

View File

@ -46,6 +46,8 @@ func GetCards(w http.ResponseWriter, r *http.Request) {
}
}
PrintMsg(response);
w.Header().Set("Card-Revision", strconv.FormatInt(account.CardRevision, 10))
WriteResponse(w, response)
}

View File

@ -146,7 +146,7 @@ type CardProfile struct {
Location string `json:"location,omitempty"`
ImageSet bool `json:"imageSet,omitempty"`
ImageSet bool `json:"imageSet"`
Version string `json:"version,omitempty"`

View File

@ -12,6 +12,10 @@ export function getProfileImageUrl(token, revision) {
return '/profile/image?agent=' + token + "&revision=" + revision
}
export function getCardImageUrl(token, cardId, revision) {
return `/contact/cards/${cardId}/profile/image?agent=${token}&revision=${revision}`
}
export function getListingImageUrl(server, guid, revision) {
return `https://${server}/account/listing/${guid}/image?revision=${revision}`
}

View File

@ -1,5 +1,5 @@
import { useEffect, useState, useRef } from 'react';
import { getCards, getCardProfile, getCardDetail, getListingImageUrl, getListing, setProfileImage, setProfileData, getProfileImageUrl, getAccountStatus, setAccountSearchable, getProfile, getGroups, getAvailable, getUsername, setLogin, createAccount } from './fetchUtil';
import { getCards, getCardImageUrl, getCardProfile, getCardDetail, getListingImageUrl, getListing, setProfileImage, setProfileData, getProfileImageUrl, getAccountStatus, setAccountSearchable, getProfile, getGroups, getAvailable, getUsername, setLogin, createAccount } from './fetchUtil';
async function updateAccount(token, updateData) {
let status = await getAccountStatus(token);
@ -14,7 +14,12 @@ async function updateProfile(token, updateData) {
async function updateGroups(token, revision, groupMap, updateData) {
let groups = await getGroups(token, revision);
for (let group of groups) {
groupMap.set(group.id, group);
if (group.data) {
groupMap.set(group.id, group);
}
else {
groupMap.delete(group.id);
}
}
updateData({ groups: Array.from(groupMap.values()) });
}
@ -22,48 +27,55 @@ async function updateGroups(token, revision, groupMap, updateData) {
async function updateCards(token, revision, cardMap, updateData) {
let cards = await getCards(token, revision);
for (let card of cards) {
let cur = cardMap.get(card.id);
if (cur == null) {
cur = { id: card.id, data: {} }
}
if (cur.data.DetailRevision != card.data.DetailRevision) {
if (card.data.CardDetail != null) {
cur.data.CardDetail = card.data.CardDetail;
if (card.data) {
let cur = cardMap.get(card.id);
if (cur == null) {
cur = { id: card.id, data: {} }
}
else {
cur.data.CardDetail = await getCardDetail(token, card.id);
if (cur.data.detailRevision != card.data.detailRevision) {
if (card.data.cardDetail != null) {
cur.data.cardDetail = card.data.cardDetail;
}
else {
cur.data.cardDetail = await getCardDetail(token, card.id);
}
cur.data.detailRevision = card.data.detailRevision;
}
cur.data.DetailRevision = card.data.DetailRevision;
}
if (cur.data.ProfileRevision != card.data.ProfileRevision) {
if (cur.data.CardProfile != null) {
cur.data.CardProfile = card.data.CardProfile;
if (cur.data.profileRevision != card.data.profileRevision) {
if (cur.data.cardProfile != null) {
cur.data.cardProfile = card.data.cardProfile;
}
else {
cur.data.cardProfile = await getCardProfile(token, card.id);
}
cur.data.profileRevision = card.data.profileRevision;
}
else {
cur.data.CardProfile = await getCardProfile(token, card.id);
if (cur.data.notifiedProfile != card.data.notifiedProfile) {
// update remote profile
cur.data.notifiedProfile = card.data.notifiedProfile;
}
cur.data.ProfileRevision = card.data.ProfileRevision;
if (cur.data.notifiedView != card.data.notifiedView) {
// update remote articles and channels
cur.data.notifiedArticle = card.data.notifiedArticle;
cur.data.notifiedChannel = card.data.notifiedChannel;
cur.data.notifiedView = card.data.notifiedView;
}
if (cur.data.notifiedArticle != card.data.notifiedArticle) {
// update remote articles
cur.data.notifiedArticle = card.data.notifiedArticle;
}
if (cur.data.notifiedChannel != card.data.notifiedChannel) {
// update remote channels
cur.data.notifiedChannel = card.data.notifiedChannel;
}
cur.revision = card.revision;
cardMap.set(card.id, cur);
}
if (cur.data.NotifiedProfile != card.data.NotifiedProfile) {
// update remote profile
cur.data.NotifiedProfile = card.data.NotifiedProfile;
else {
cardMap.delete(card.id);
}
if (cur.data.NotifiedView != card.data.NotifiedView) {
// update remote articles and channels
cur.data.NotifiedArticle = card.data.NotifiedArticle;
cur.data.NotifiedChannel = card.data.NotifiedChannel;
cur.data.NotifiedView = card.data.NotifiedView;
}
if (cur.data.NotifiedArticle != card.data.NotifiedArticle) {
// update remote articles
cur.data.NotifiedArticle = card.data.NotifiedArticle;
}
if (cur.data.NotifiedChannel != card.data.NotifiedChannel) {
// update remote channels
cur.data.NotifiedChannel = card.data.NotifiedChannel;
}
cur.revision = card.revision;
}
updateData({ cards: Array.from(cardMap.values()) });
}
async function appCreate(username, password, updateState, setWebsocket) {
@ -140,6 +152,7 @@ export function useAppContext() {
profileImageUrl: () => getProfileImageUrl(state.token, state.Data?.profile?.revision),
getRegistry: async (node) => getListing(node),
getRegistryImageUrl: (server, guid, revision) => getListingImageUrl(server, guid, revision),
getCardImageUrl: (cardId, revision) => getCardImageUrl(state.token, cardId, revision),
}
const adminActions = {

View File

@ -1,28 +1,70 @@
import React, { useEffect } from 'react'
import { CardsWrapper } from './Cards.styled';
import { Drawer } from 'antd';
import { CardsWrapper, CardItem } from './Cards.styled';
import { Drawer, List } from 'antd';
import { Registry } from './Registry/Registry';
import { useCards } from './useCards.hook';
import { Logo } from '../../../../Logo/Logo';
export function Cards({ showRegistry }) {
const { state, actions } = useCards();
useEffect(() => {
}, [showRegistry]);
const onSelect = (item) => {
actions.select(item);
}
const cardProfile = (item) => {
if (item?.data?.cardProfile) {
return item.data.cardProfile;
}
return {}
}
const cardImage = (item) => {
if (actions?.getCardImageUrl) {
return actions.getCardImageUrl(item.id, item.revision);
}
else {
return null
}
}
return (
<CardsWrapper>
<div>
<Drawer
placement="right"
closable={false}
visible={showRegistry}
getContainer={false}
contentWrapperStyle={{ width: '100%' }}
bodyStyle={{ backgroundColor: '#f6f5ed', paddingLeft: 16, paddingRight: 16, paddingTop: 16, paddingBottom: 0 }}
style={{ position: 'absolute' }}
>
<Registry />
</Drawer>
</div>
<Drawer
placement="right"
closable={false}
visible={showRegistry}
getContainer={false}
contentWrapperStyle={{ width: '100%' }}
bodyStyle={{ backgroundColor: '#f6f5ed', paddingLeft: 16, paddingRight: 16, paddingTop: 16, paddingBottom: 0 }}
style={{ position: 'absolute' }}
>
<Registry />
</Drawer>
<List
locale={{ emptyText: '' }}
itemLayout="horizontal"
dataSource={state.cards}
gutter="0"
renderItem={item => (
<CardItem onClick={() => onSelect(item)}>
<div class="item">
<div class="logo">
<Logo imageUrl={cardImage(item)}
imageSet={cardProfile(item).imageSet} />
</div>
<div class="username">
<span class="handle">{ cardProfile(item).handle }</span>
<span class="name">{ cardProfile(item).name }</span>
</div>
</div>
</CardItem>
)}
/>
</CardsWrapper>
)
}

View File

@ -1,4 +1,4 @@
import { Button } from 'antd';
import { Button, List } from 'antd';
import styled from 'styled-components';
export const CardsWrapper = styled.div`
@ -11,3 +11,43 @@ export const CardsWrapper = styled.div`
padding-top: 16px;
`;
export const CardItem = styled(List.Item)`
padding-left: 16px;
padding-right: 16px;
padding-top: 4px;
padding-bottom: 4px;
cursor: pointer;
&:hover {
background-color: #eeeeee;
}
.item {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
}
.logo {
width: 36px;
height: 36px;
}
.username {
display: flex;
flex-direction: column;
padding-left: 16px;
text-align: right;
flex-grow: 1;
}
.name {
font-size: 1em;
}
.handle {
font-size: 0.9em;
font-weight: bold;
}
`;

View File

@ -0,0 +1,35 @@
import { useContext, useState, useEffect } from 'react';
import { AppContext } from '../../../../AppContext/AppContext';
import { useNavigate } from 'react-router-dom';
export function useCards() {
const [state, setState] = useState({
cards: [],
});
const navigate = useNavigate();
const app = useContext(AppContext);
const actions = {
getCardImageUrl: app?.actions?.getCardImageUrl,
select: (contact) => {
navigate(`/user/contact/${contact.data.cardProfile.guid}`);
}
};
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
useEffect(() => {
if (app?.state?.Data?.cards) {
updateState({ cards: app.state.Data.cards });
}
else {
updateState({ cards: [] });
}
}, [app])
return { state, actions };
}