diff --git a/net/server/internal/api_getCardImage.go b/net/server/internal/api_getCardImage.go index 9a7895eb..5e181cb8 100644 --- a/net/server/internal/api_getCardImage.go +++ b/net/server/internal/api_getCardImage.go @@ -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 diff --git a/net/server/internal/api_getCards.go b/net/server/internal/api_getCards.go index f9fff2c6..dd065d46 100644 --- a/net/server/internal/api_getCards.go +++ b/net/server/internal/api_getCards.go @@ -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) } diff --git a/net/server/internal/models.go b/net/server/internal/models.go index 98d14660..24073d59 100644 --- a/net/server/internal/models.go +++ b/net/server/internal/models.go @@ -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"` diff --git a/net/web/src/AppContext/fetchUtil.js b/net/web/src/AppContext/fetchUtil.js index f8d1c9c2..2128baae 100644 --- a/net/web/src/AppContext/fetchUtil.js +++ b/net/web/src/AppContext/fetchUtil.js @@ -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}` } diff --git a/net/web/src/AppContext/useAppContext.hook.js b/net/web/src/AppContext/useAppContext.hook.js index 1180c206..2ad0906d 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 { 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 = { diff --git a/net/web/src/User/SideBar/Contacts/Cards/Cards.jsx b/net/web/src/User/SideBar/Contacts/Cards/Cards.jsx index c654c1a6..86a192d8 100644 --- a/net/web/src/User/SideBar/Contacts/Cards/Cards.jsx +++ b/net/web/src/User/SideBar/Contacts/Cards/Cards.jsx @@ -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 ( -
- - - -
+ + + + ( + onSelect(item)}> +
+ +
+ { cardProfile(item).handle } + { cardProfile(item).name } +
+
+
+ )} + />
) } diff --git a/net/web/src/User/SideBar/Contacts/Cards/Cards.styled.js b/net/web/src/User/SideBar/Contacts/Cards/Cards.styled.js index c459cca7..02bd1dc6 100644 --- a/net/web/src/User/SideBar/Contacts/Cards/Cards.styled.js +++ b/net/web/src/User/SideBar/Contacts/Cards/Cards.styled.js @@ -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; + } +`; + diff --git a/net/web/src/User/SideBar/Contacts/Cards/useCards.hook.js b/net/web/src/User/SideBar/Contacts/Cards/useCards.hook.js new file mode 100644 index 00000000..521cb844 --- /dev/null +++ b/net/web/src/User/SideBar/Contacts/Cards/useCards.hook.js @@ -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 }; +}