mirror of
https://github.com/urbit/shrub.git
synced 2024-12-19 16:51:42 +03:00
interface: covert contact store to zustand
This commit is contained in:
parent
72aa7f5aee
commit
12645644f7
@ -2,8 +2,9 @@ import { useEffect, useState } from 'react';
|
||||
import _ from 'lodash';
|
||||
import f, { memoize } from 'lodash/fp';
|
||||
import bigInt, { BigInteger } from 'big-integer';
|
||||
import { Contact } from '@urbit/api';
|
||||
import { Association, Contact } from '@urbit/api';
|
||||
import useLocalState from '../state/local';
|
||||
import produce from 'immer';
|
||||
|
||||
export const MOBILE_BROWSER_REGEX = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i;
|
||||
|
||||
@ -408,3 +409,8 @@ export function getItemTitle(association: Association) {
|
||||
}
|
||||
return association.metadata.title || association.resource;
|
||||
}
|
||||
|
||||
export const stateSetter = <StateType>(fn: (state: StateType) => void, set): void => {
|
||||
// TODO this is a stub for the store debugging
|
||||
return set(produce(fn));
|
||||
};
|
@ -1,44 +1,53 @@
|
||||
import _ from 'lodash';
|
||||
import { StoreState } from '../../store/type';
|
||||
import { Cage } from '~/types/cage';
|
||||
import { ContactUpdate } from '@urbit/api/contacts';
|
||||
import { resourceAsPath } from '../lib/util';
|
||||
import { compose } from 'lodash/fp';
|
||||
|
||||
type ContactState = Pick<StoreState, 'contacts'>;
|
||||
import { ContactUpdate } from '@urbit/api';
|
||||
|
||||
export const ContactReducer = (json, state) => {
|
||||
const data = _.get(json, 'contact-update', false);
|
||||
import useContactState, { ContactState } from '../state/contacts';
|
||||
|
||||
|
||||
export const ContactReducer = (json) => {
|
||||
const data: ContactUpdate = _.get(json, 'contact-update', false);
|
||||
if (data) {
|
||||
initial(data, state);
|
||||
add(data, state);
|
||||
remove(data, state);
|
||||
edit(data, state);
|
||||
setPublic(data, state);
|
||||
useContactState.setState(
|
||||
compose([
|
||||
initial,
|
||||
add,
|
||||
remove,
|
||||
edit,
|
||||
setPublic
|
||||
].map(reducer => reducer.bind(reducer, data))
|
||||
)(useContactState.getState())
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: better isolation
|
||||
const res = _.get(json, 'resource', false);
|
||||
if(res) {
|
||||
state.nackedContacts = state.nackedContacts.add(`~${res.ship}`);
|
||||
if (res) {
|
||||
useContactState.setState({
|
||||
nackedContacts: useContactState.getState().nackedContacts.add(`~${res.ship}`)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const initial = (json: ContactUpdate, state: S) => {
|
||||
const initial = (json: ContactUpdate, state: ContactState): ContactState => {
|
||||
const data = _.get(json, 'initial', false);
|
||||
if (data) {
|
||||
state.contacts = data.rolodex;
|
||||
state.isContactPublic = data['is-public'];
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
const add = (json: ContactUpdate, state: S) => {
|
||||
const add = (json: ContactUpdate, state: ContactState): ContactState => {
|
||||
const data = _.get(json, 'add', false);
|
||||
if (data) {
|
||||
state.contacts[data.ship] = data.contact;
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
const remove = (json: ContactUpdate, state: S) => {
|
||||
const remove = (json: ContactUpdate, state: ContactState): ContactState => {
|
||||
const data = _.get(json, 'remove', false);
|
||||
if (
|
||||
data &&
|
||||
@ -46,9 +55,10 @@ const remove = (json: ContactUpdate, state: S) => {
|
||||
) {
|
||||
delete state.contacts[data.ship];
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
const edit = (json: ContactUpdate, state: S) => {
|
||||
const edit = (json: ContactUpdate, state: ContactState): ContactState => {
|
||||
const data = _.get(json, 'edit', false);
|
||||
const ship = `~${data.ship}`;
|
||||
if (
|
||||
@ -57,7 +67,7 @@ const edit = (json: ContactUpdate, state: S) => {
|
||||
) {
|
||||
const [field] = Object.keys(data['edit-field']);
|
||||
if (!field) {
|
||||
return;
|
||||
return state;
|
||||
}
|
||||
|
||||
const value = data['edit-field'][field];
|
||||
@ -71,10 +81,12 @@ const edit = (json: ContactUpdate, state: S) => {
|
||||
state.contacts[ship][field] = value;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
const setPublic = (json: ContactUpdate, state: S) => {
|
||||
const setPublic = (json: ContactUpdate, state: ContactState): ContactState => {
|
||||
const data = _.get(json, 'set-public', state.isContactPublic);
|
||||
state.isContactPublic = data;
|
||||
return state;
|
||||
};
|
||||
|
||||
|
51
pkg/interface/src/logic/state/contacts.tsx
Normal file
51
pkg/interface/src/logic/state/contacts.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import React from "react";
|
||||
import create, { State } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
import { Patp, Rolodex, Scry } from "@urbit/api";
|
||||
|
||||
import { stateSetter } from "~/logic/lib/util";
|
||||
// import useApi from "~/logic/lib/useApi";
|
||||
|
||||
export interface ContactState extends State {
|
||||
contacts: Rolodex;
|
||||
isContactPublic: boolean;
|
||||
nackedContacts: Set<Patp>;
|
||||
// fetchIsAllowed: (entity, name, ship, personal) => Promise<boolean>;
|
||||
set: (fn: (state: ContactState) => void) => void;
|
||||
};
|
||||
|
||||
const useContactState = create<ContactState>(persist((set, get) => ({
|
||||
contacts: {},
|
||||
nackedContacts: new Set(),
|
||||
isContactPublic: false,
|
||||
// fetchIsAllowed: async (
|
||||
// entity,
|
||||
// name,
|
||||
// ship,
|
||||
// personal
|
||||
// ): Promise<boolean> => {
|
||||
// const isPersonal = personal ? 'true' : 'false';
|
||||
// const api = useApi();
|
||||
// return api.scry({
|
||||
// app: 'contact-store',
|
||||
// path: `/is-allowed/${entity}/${name}/${ship}/${isPersonal}`
|
||||
// });
|
||||
// },
|
||||
set: fn => stateSetter(fn, set)
|
||||
}), {
|
||||
name: 'LandscapeContactState'
|
||||
}));
|
||||
|
||||
function withContactState<P, S extends keyof ContactState>(Component: any, stateMemberKeys?: S[]) {
|
||||
return React.forwardRef((props: Omit<P, S>, ref) => {
|
||||
const contactState = stateMemberKeys ? useContactState(
|
||||
state => stateMemberKeys.reduce(
|
||||
(object, key) => ({ ...object, [key]: state[key] }), {}
|
||||
)
|
||||
): useContactState();
|
||||
return <Component ref={ref} {...contactState} {...props} />
|
||||
});
|
||||
}
|
||||
|
||||
export { useContactState as default, withContactState };
|
@ -77,9 +77,6 @@ export default class GlobalStore extends BaseStore<StoreState> {
|
||||
},
|
||||
credentials: null
|
||||
},
|
||||
isContactPublic: false,
|
||||
contacts: {},
|
||||
nackedContacts: new Set(),
|
||||
notifications: new BigIntOrderedMap<Timebox>(),
|
||||
archivedNotifications: new BigIntOrderedMap<Timebox>(),
|
||||
notificationsGroupConfig: [],
|
||||
@ -113,7 +110,7 @@ export default class GlobalStore extends BaseStore<StoreState> {
|
||||
this.connReducer.reduce(data, this.state);
|
||||
GraphReducer(data, this.state);
|
||||
HarkReducer(data, this.state);
|
||||
ContactReducer(data, this.state);
|
||||
ContactReducer(data);
|
||||
this.settingsReducer.reduce(data, this.state);
|
||||
GroupViewReducer(data, this.state);
|
||||
}
|
||||
|
@ -25,12 +25,9 @@ export interface StoreState {
|
||||
invites: Invites;
|
||||
// metadata state
|
||||
associations: Associations;
|
||||
// contact state
|
||||
contacts: Rolodex;
|
||||
// groups state
|
||||
groups: Groups;
|
||||
groupKeys: Set<Path>;
|
||||
nackedContacts: Set<Patp>
|
||||
s3: S3State;
|
||||
graphs: Graphs;
|
||||
graphKeys: Set<string>;
|
||||
|
@ -28,6 +28,7 @@ import GlobalApi from '~/logic/api/global';
|
||||
import { uxToHex } from '~/logic/lib/util';
|
||||
import { foregroundFromBackground } from '~/logic/lib/sigil';
|
||||
import { withLocalState } from '~/logic/state/local';
|
||||
import { withContactState } from '~/logic/state/contacts';
|
||||
|
||||
|
||||
const Root = styled.div`
|
||||
@ -116,8 +117,8 @@ class App extends React.Component {
|
||||
|
||||
faviconString() {
|
||||
let background = '#ffffff';
|
||||
if (this.state.contacts.hasOwnProperty('/~/default')) {
|
||||
background = `#${uxToHex(this.state.contacts['/~/default'][window.ship].color)}`;
|
||||
if (this.props.contacts.hasOwnProperty('/~/default')) {
|
||||
background = `#${uxToHex(this.props.contacts['/~/default'][window.ship].color)}`;
|
||||
}
|
||||
const foreground = foregroundFromBackground(background);
|
||||
const svg = sigiljs({
|
||||
@ -139,7 +140,7 @@ class App extends React.Component {
|
||||
|
||||
const notificationsCount = state.notificationsCount || 0;
|
||||
const doNotDisturb = state.doNotDisturb || false;
|
||||
const ourContact = this.state.contacts[`~${this.ship}`] || null;
|
||||
const ourContact = this.props.contacts[`~${this.ship}`] || null;
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
@ -171,7 +172,6 @@ class App extends React.Component {
|
||||
apps={state.launch}
|
||||
tiles={state.launch.tiles}
|
||||
api={this.api}
|
||||
contacts={state.contacts}
|
||||
notifications={state.notificationsCount}
|
||||
invites={state.invites}
|
||||
groups={state.groups}
|
||||
@ -195,5 +195,5 @@ class App extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default withLocalState(process.env.NODE_ENV === 'production' ? App : hot(App));
|
||||
export default withContactState(withLocalState(process.env.NODE_ENV === 'production' ? App : hot(App)));
|
||||
|
||||
|
@ -17,6 +17,7 @@ import useS3 from '~/logic/lib/useS3';
|
||||
import { isWriter, resourceFromPath } from '~/logic/lib/group';
|
||||
|
||||
import './css/custom.css';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
type ChatResourceProps = StoreState & {
|
||||
association: Association;
|
||||
@ -28,7 +29,7 @@ export function ChatResource(props: ChatResourceProps) {
|
||||
const station = props.association.resource;
|
||||
const groupPath = props.association.group;
|
||||
const group = props.groups[groupPath];
|
||||
const contacts = props.contacts;
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
const graph = props.graphs[station.slice(7)];
|
||||
const isChatMissing = !props.graphKeys.has(station.slice(7));
|
||||
const unreadCount = props.unreads.graph?.[station]?.['/']?.unreads || 0;
|
||||
|
@ -18,7 +18,6 @@ type ChatInputProps = IuseS3 & {
|
||||
station: unknown;
|
||||
ourContact: unknown;
|
||||
envelopes: Envelope[];
|
||||
contacts: Contacts;
|
||||
onUnmount(msg: string): void;
|
||||
s3: unknown;
|
||||
placeholder: string;
|
||||
|
@ -33,6 +33,7 @@ import { Mention } from '~/views/components/MentionText';
|
||||
import styled from 'styled-components';
|
||||
import useLocalState from '~/logic/state/local';
|
||||
import Timestamp from '~/views/components/Timestamp';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
export const DATESTAMP_FORMAT = '[~]YYYY.M.D';
|
||||
|
||||
@ -85,7 +86,6 @@ interface ChatMessageProps {
|
||||
isLastRead: boolean;
|
||||
group: Group;
|
||||
association: Association;
|
||||
contacts: Contacts;
|
||||
className?: string;
|
||||
isPending: boolean;
|
||||
style?: unknown;
|
||||
@ -120,7 +120,6 @@ export default class ChatMessage extends Component<ChatMessageProps> {
|
||||
isLastRead,
|
||||
group,
|
||||
association,
|
||||
contacts,
|
||||
className = '',
|
||||
isPending,
|
||||
style,
|
||||
@ -164,7 +163,6 @@ export default class ChatMessage extends Component<ChatMessageProps> {
|
||||
const messageProps = {
|
||||
msg,
|
||||
timestamp,
|
||||
contacts,
|
||||
association,
|
||||
group,
|
||||
measure: reboundMeasure.bind(this),
|
||||
@ -219,7 +217,6 @@ export default class ChatMessage extends Component<ChatMessageProps> {
|
||||
|
||||
export const MessageAuthor = ({
|
||||
timestamp,
|
||||
contacts,
|
||||
msg,
|
||||
measure,
|
||||
group,
|
||||
@ -231,6 +228,7 @@ export const MessageAuthor = ({
|
||||
...rest
|
||||
}) => {
|
||||
const dark = useLocalState((state) => state.dark);
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
|
||||
const datestamp = moment
|
||||
.unix(msg['time-sent'] / 1000)
|
||||
@ -364,7 +362,6 @@ export const MessageAuthor = ({
|
||||
|
||||
export const Message = ({
|
||||
timestamp,
|
||||
contacts,
|
||||
msg,
|
||||
measure,
|
||||
group,
|
||||
@ -376,6 +373,7 @@ export const Message = ({
|
||||
...rest
|
||||
}) => {
|
||||
const { hovering, bind } = useHovering();
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
return (
|
||||
<Box position='relative' {...rest}>
|
||||
{timestampHover ? (
|
||||
|
@ -32,7 +32,6 @@ type ChatWindowProps = RouteComponentProps<{
|
||||
}> & {
|
||||
unreadCount: number;
|
||||
graph: Graph;
|
||||
contacts: Contacts;
|
||||
association: Association;
|
||||
group: Group;
|
||||
ship: Patp;
|
||||
@ -240,11 +239,8 @@ export default class ChatWindow extends Component<
|
||||
const {
|
||||
unreadCount,
|
||||
api,
|
||||
ship,
|
||||
station,
|
||||
association,
|
||||
group,
|
||||
contacts,
|
||||
graph,
|
||||
history,
|
||||
groups,
|
||||
@ -255,7 +251,6 @@ export default class ChatWindow extends Component<
|
||||
const messageProps = {
|
||||
association,
|
||||
group,
|
||||
contacts,
|
||||
unreadMarkerRef,
|
||||
history,
|
||||
api,
|
||||
|
@ -7,7 +7,6 @@ import { deSig } from '~/logic/lib/util';
|
||||
export default class GraphApp extends PureComponent {
|
||||
render() {
|
||||
const { props } = this;
|
||||
const contacts = props.contacts ? props.contacts : {};
|
||||
const groups = props.groups ? props.groups : {};
|
||||
const associations =
|
||||
props.associations ? props.associations : { graph: {}, contacts: {} };
|
||||
|
@ -7,7 +7,7 @@ import _ from 'lodash';
|
||||
import { Col, Button, Box, Row, Icon, Text } from '@tlon/indigo-react';
|
||||
|
||||
import './css/custom.css';
|
||||
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
import Tiles from './components/tiles';
|
||||
import Tile from './components/tiles/tile';
|
||||
import Groups from './components/Groups';
|
||||
@ -41,7 +41,6 @@ const ScrollbarLessBox = styled(Box)`
|
||||
const tutSelector = f.pick(['tutorialProgress', 'nextTutStep']);
|
||||
|
||||
export default function LaunchApp(props) {
|
||||
const history = useHistory();
|
||||
const [hashText, setHashText] = useState(props.baseHash);
|
||||
const hashBox = (
|
||||
<Box
|
||||
@ -133,7 +132,8 @@ export default function LaunchApp(props) {
|
||||
</Col>
|
||||
)}
|
||||
});
|
||||
const hasLoaded = useMemo(() => Object.keys(props.contacts).length > 0, [props.contacts]);
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
const hasLoaded = useMemo(() => Object.keys(contacts).length > 0, [contacts]);
|
||||
|
||||
useEffect(() => {
|
||||
const seenTutorial = _.get(props.settings, ['tutorial', 'seen'], true);
|
||||
|
@ -28,7 +28,6 @@ export function LinkResource(props: LinkResourceProps) {
|
||||
api,
|
||||
baseUrl,
|
||||
graphs,
|
||||
contacts,
|
||||
groups,
|
||||
associations,
|
||||
graphKeys,
|
||||
@ -70,7 +69,6 @@ export function LinkResource(props: LinkResourceProps) {
|
||||
<LinkWindow
|
||||
s3={s3}
|
||||
association={resource}
|
||||
contacts={contacts}
|
||||
resource={resourcePath}
|
||||
graph={graph}
|
||||
unreads={unreads}
|
||||
@ -103,7 +101,6 @@ export function LinkResource(props: LinkResourceProps) {
|
||||
<Col width="100%" p={3} maxWidth="768px">
|
||||
<Link to={resourceUrl}><Text px={3} bold>{'<- Back'}</Text></Link>
|
||||
<LinkItem
|
||||
contacts={contacts}
|
||||
key={node.post.index}
|
||||
resource={resourcePath}
|
||||
node={node}
|
||||
@ -122,7 +119,6 @@ export function LinkResource(props: LinkResourceProps) {
|
||||
resource={resourcePath}
|
||||
association={association}
|
||||
unreads={unreads}
|
||||
contacts={contacts}
|
||||
api={api}
|
||||
editCommentId={editCommentId}
|
||||
history={props.history}
|
||||
|
@ -17,7 +17,6 @@ interface LinkItemProps {
|
||||
api: GlobalApi;
|
||||
group: Group;
|
||||
path: string;
|
||||
contacts: Rolodex;
|
||||
unreads: Unreads;
|
||||
measure: (el: any) => void;
|
||||
}
|
||||
@ -29,7 +28,6 @@ export const LinkItem = (props: LinkItemProps): ReactElement => {
|
||||
api,
|
||||
group,
|
||||
path,
|
||||
contacts,
|
||||
measure,
|
||||
...rest
|
||||
} = props;
|
||||
@ -157,7 +155,6 @@ export const LinkItem = (props: LinkItemProps): ReactElement => {
|
||||
|
||||
<Author
|
||||
showImage
|
||||
contacts={contacts}
|
||||
ship={author}
|
||||
date={node.post['time-sent']}
|
||||
group={group}
|
||||
|
@ -18,6 +18,7 @@ import { getSnippet } from '~/logic/lib/publish';
|
||||
import styled from 'styled-components';
|
||||
import { MentionText } from '~/views/components/MentionText';
|
||||
import ChatMessage from '../chat/components/ChatMessage';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
function getGraphModuleIcon(module: string) {
|
||||
if (module === 'link') {
|
||||
@ -67,7 +68,6 @@ const GraphUrl = ({ url, title }) => (
|
||||
const GraphNodeContent = ({
|
||||
group,
|
||||
post,
|
||||
contacts,
|
||||
mod,
|
||||
description,
|
||||
index,
|
||||
@ -81,7 +81,7 @@ const GraphNodeContent = ({
|
||||
return <GraphUrl title={text} url={url} />;
|
||||
} else if (idx.length === 3) {
|
||||
return (
|
||||
<MentionText content={contents} contacts={contacts} group={group} />
|
||||
<MentionText content={contents} group={group} />
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@ -92,7 +92,6 @@ const GraphNodeContent = ({
|
||||
<MentionText
|
||||
content={contents}
|
||||
group={group}
|
||||
contacts={contacts}
|
||||
fontSize='14px'
|
||||
lineHeight='tall'
|
||||
/>
|
||||
@ -134,7 +133,6 @@ const GraphNodeContent = ({
|
||||
containerClass='items-top cf hide-child'
|
||||
measure={() => {}}
|
||||
group={group}
|
||||
contacts={contacts}
|
||||
groups={{}}
|
||||
associations={{ graph: {}, groups: {} }}
|
||||
msg={post}
|
||||
@ -174,7 +172,6 @@ function getNodeUrl(
|
||||
}
|
||||
const GraphNode = ({
|
||||
post,
|
||||
contacts,
|
||||
author,
|
||||
mod,
|
||||
description,
|
||||
@ -189,6 +186,7 @@ const GraphNode = ({
|
||||
}) => {
|
||||
author = deSig(author);
|
||||
const history = useHistory();
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
|
||||
const nodeUrl = getNodeUrl(mod, group?.hidden, groupPath, graph, index);
|
||||
|
||||
@ -207,7 +205,6 @@ const GraphNode = ({
|
||||
{showContact && (
|
||||
<Author
|
||||
showImage
|
||||
contacts={contacts}
|
||||
ship={author}
|
||||
date={time}
|
||||
group={group}
|
||||
@ -215,7 +212,6 @@ const GraphNode = ({
|
||||
)}
|
||||
<Row width='100%' p='1' flexDirection='column'>
|
||||
<GraphNodeContent
|
||||
contacts={contacts}
|
||||
post={post}
|
||||
mod={mod}
|
||||
description={description}
|
||||
@ -238,7 +234,6 @@ export function GraphNotification(props: {
|
||||
timebox: BigInteger;
|
||||
associations: Associations;
|
||||
groups: Groups;
|
||||
contacts: Rolodex;
|
||||
api: GlobalApi;
|
||||
}) {
|
||||
const { contents, index, read, time, api, timebox, groups } = props;
|
||||
@ -266,7 +261,6 @@ export function GraphNotification(props: {
|
||||
authors={authors}
|
||||
moduleIcon={icon}
|
||||
channel={graph}
|
||||
contacts={props.contacts}
|
||||
group={group}
|
||||
description={desc}
|
||||
associations={props.associations}
|
||||
@ -276,7 +270,6 @@ export function GraphNotification(props: {
|
||||
<GraphNode
|
||||
post={content}
|
||||
author={content.author}
|
||||
contacts={props.contacts}
|
||||
mod={index.module}
|
||||
time={content?.['time-sent']}
|
||||
description={index.description}
|
||||
|
@ -69,7 +69,6 @@ export function GroupNotification(props: GroupNotificationProps): ReactElement {
|
||||
time={time}
|
||||
read={read}
|
||||
group={group}
|
||||
contacts={props.contacts}
|
||||
authors={authors}
|
||||
description={desc}
|
||||
associations={associations}
|
||||
|
@ -9,13 +9,15 @@ import { Associations, Contact, Contacts, Rolodex } from '@urbit/api';
|
||||
import { PropFunc } from '~/types/util';
|
||||
import { useShowNickname } from '~/logic/lib/util';
|
||||
import Timestamp from '~/views/components/Timestamp';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
const Text = (props: PropFunc<typeof Text>) => (
|
||||
<NormalText fontWeight="500" {...props} />
|
||||
);
|
||||
|
||||
function Author(props: { patp: string; contacts: Contacts; last?: boolean }): ReactElement {
|
||||
const contact: Contact | undefined = props.contacts?.[`~${props.patp}`];
|
||||
function Author(props: { patp: string; last?: boolean }): ReactElement {
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
const contact: Contact | undefined = contacts?.[`~${props.patp}`];
|
||||
|
||||
const showNickname = useShowNickname(contact);
|
||||
const name = contact?.nickname || `~${props.patp}`;
|
||||
@ -33,14 +35,13 @@ export function Header(props: {
|
||||
archived?: boolean;
|
||||
channel?: string;
|
||||
group: string;
|
||||
contacts: Rolodex;
|
||||
description: string;
|
||||
moduleIcon?: string;
|
||||
time: number;
|
||||
read: boolean;
|
||||
associations: Associations;
|
||||
} & PropFunc<typeof Row> ): ReactElement {
|
||||
const { description, channel, contacts, moduleIcon, read } = props;
|
||||
const { description, channel, moduleIcon, read } = props;
|
||||
|
||||
const authors = _.uniq(props.authors);
|
||||
|
||||
@ -50,7 +51,7 @@ export function Header(props: {
|
||||
f.map(([idx, p]: [string, string]) => {
|
||||
const lent = Math.min(3, authors.length);
|
||||
const last = lent - 1 === parseInt(idx, 10);
|
||||
return <Author key={idx} contacts={contacts} patp={p} last={last} />;
|
||||
return <Author key={idx} patp={p} last={last} />;
|
||||
}),
|
||||
auths => (
|
||||
<React.Fragment>
|
||||
|
@ -50,7 +50,6 @@ export default function Inbox(props: {
|
||||
showArchive?: boolean;
|
||||
api: GlobalApi;
|
||||
associations: Associations;
|
||||
contacts: Rolodex;
|
||||
filter: string[];
|
||||
invites: InviteType;
|
||||
pendingJoin: JoinRequests;
|
||||
@ -127,7 +126,6 @@ export default function Inbox(props: {
|
||||
key={day}
|
||||
label={day === 'latest' ? 'Today' : moment(day).calendar(null, calendar)}
|
||||
timeboxes={timeboxes}
|
||||
contacts={props.contacts}
|
||||
archive={Boolean(props.showArchive)}
|
||||
associations={props.associations}
|
||||
api={api}
|
||||
@ -165,7 +163,6 @@ function sortIndexedNotification(
|
||||
|
||||
function DaySection({
|
||||
label,
|
||||
contacts,
|
||||
groups,
|
||||
archive,
|
||||
timeboxes,
|
||||
@ -201,7 +198,6 @@ function DaySection({
|
||||
associations={associations}
|
||||
notification={not}
|
||||
archived={archive}
|
||||
contacts={contacts}
|
||||
groups={groups}
|
||||
time={date}
|
||||
/>
|
||||
|
@ -12,7 +12,6 @@ interface InvitesProps {
|
||||
api: GlobalApi;
|
||||
invites: IInvites;
|
||||
groups: Groups;
|
||||
contacts: Contacts;
|
||||
associations: Associations;
|
||||
pendingJoin: JoinRequests;
|
||||
}
|
||||
@ -54,7 +53,6 @@ export function Invites(props: InvitesProps): ReactElement {
|
||||
return (
|
||||
<InviteItem
|
||||
key={resource}
|
||||
contacts={props.contacts}
|
||||
groups={props.groups}
|
||||
associations={props.associations}
|
||||
resource={resource}
|
||||
@ -74,7 +72,6 @@ export function Invites(props: InvitesProps): ReactElement {
|
||||
uid={uid}
|
||||
pendingJoin={pendingJoin}
|
||||
resource={resource}
|
||||
contacts={props.contacts}
|
||||
groups={props.groups}
|
||||
associations={props.associations}
|
||||
/>
|
||||
|
@ -26,7 +26,6 @@ interface NotificationProps {
|
||||
api: GlobalApi;
|
||||
archived: boolean;
|
||||
groups: Groups;
|
||||
contacts: Contacts;
|
||||
graphConfig: NotificationGraphConfig;
|
||||
groupConfig: GroupNotificationsConfig;
|
||||
}
|
||||
@ -136,7 +135,6 @@ export function Notification(props: NotificationProps) {
|
||||
api={props.api}
|
||||
index={index}
|
||||
contents={c}
|
||||
contacts={props.contacts}
|
||||
groups={props.groups}
|
||||
read={read}
|
||||
archived={archived}
|
||||
@ -156,7 +154,6 @@ export function Notification(props: NotificationProps) {
|
||||
api={props.api}
|
||||
index={index}
|
||||
contents={c}
|
||||
contacts={props.contacts}
|
||||
groups={props.groups}
|
||||
read={read}
|
||||
timebox={props.time}
|
||||
|
@ -5,8 +5,10 @@ import Helmet from 'react-helmet';
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
|
||||
import { Profile } from './components/Profile';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
export default function ProfileScreen(props: any) {
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
return (
|
||||
<>
|
||||
<Helmet defer={false}>
|
||||
@ -18,7 +20,7 @@ export default function ProfileScreen(props: any) {
|
||||
const ship = match.params.ship;
|
||||
const isEdit = match.url.includes('edit');
|
||||
const isPublic = props.isContactPublic;
|
||||
const contact = props.contacts?.[ship];
|
||||
const contact = contacts?.[ship];
|
||||
|
||||
return (
|
||||
<Box height="100%" px={[0, 3]} pb={[0, 3]} borderRadius={1}>
|
||||
@ -35,7 +37,7 @@ export default function ProfileScreen(props: any) {
|
||||
<Box>
|
||||
<Profile
|
||||
ship={ship}
|
||||
hasLoaded={Object.keys(props.contacts).length !== 0}
|
||||
hasLoaded={Object.keys(contacts).length !== 0}
|
||||
associations={props.associations}
|
||||
groups={props.groups}
|
||||
contact={contact}
|
||||
|
@ -24,7 +24,6 @@ export function PublishResource(props: PublishResourceProps) {
|
||||
api={api}
|
||||
ship={ship}
|
||||
book={book}
|
||||
contacts={props.contacts}
|
||||
groups={props.groups}
|
||||
associations={props.associations}
|
||||
association={association}
|
||||
|
@ -22,7 +22,6 @@ interface MetadataFormProps {
|
||||
host: string;
|
||||
book: string;
|
||||
association: Association;
|
||||
contacts: Contacts;
|
||||
api: GlobalApi;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,6 @@ interface NoteProps {
|
||||
unreads: Unreads;
|
||||
association: Association;
|
||||
notebook: Graph;
|
||||
contacts: Contacts;
|
||||
api: GlobalApi;
|
||||
rootUrl: string;
|
||||
baseUrl: string;
|
||||
@ -29,7 +28,7 @@ interface NoteProps {
|
||||
export function Note(props: NoteProps & RouteComponentProps) {
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
|
||||
const { notebook, note, contacts, ship, book, api, rootUrl, baseUrl, group } = props;
|
||||
const { notebook, note, ship, book, api, rootUrl, baseUrl, group } = props;
|
||||
const editCommentId = props.match.params.commentId;
|
||||
|
||||
const deletePost = async () => {
|
||||
@ -100,7 +99,6 @@ export function Note(props: NoteProps & RouteComponentProps) {
|
||||
<Box display="flex">
|
||||
<Author
|
||||
ship={post?.author}
|
||||
contacts={contacts}
|
||||
date={post?.['time-sent']}
|
||||
/>
|
||||
<Text ml={2}>{adminLinks}</Text>
|
||||
@ -120,7 +118,6 @@ export function Note(props: NoteProps & RouteComponentProps) {
|
||||
name={props.book}
|
||||
unreads={props.unreads}
|
||||
comments={comments}
|
||||
contacts={props.contacts}
|
||||
association={props.association}
|
||||
api={props.api}
|
||||
baseUrl={baseUrl}
|
||||
|
@ -21,7 +21,6 @@ interface NotePreviewProps {
|
||||
node: GraphNode;
|
||||
baseUrl: string;
|
||||
unreads: Unreads;
|
||||
contacts: Contacts;
|
||||
api: GlobalApi;
|
||||
group: Group;
|
||||
}
|
||||
@ -31,7 +30,7 @@ const WrappedBox = styled(Box)`
|
||||
`;
|
||||
|
||||
export function NotePreview(props: NotePreviewProps) {
|
||||
const { node, contacts, group } = props;
|
||||
const { node, group } = props;
|
||||
const { post } = node;
|
||||
if (!post) {
|
||||
return null;
|
||||
@ -79,7 +78,6 @@ export function NotePreview(props: NotePreviewProps) {
|
||||
<Row minWidth='0' flexShrink={0} width="100%" justifyContent="space-between" py={3} bg="white">
|
||||
<Author
|
||||
showImage
|
||||
contacts={contacts}
|
||||
ship={post?.author}
|
||||
date={post?.['time-sent']}
|
||||
group={group}
|
||||
|
@ -14,7 +14,6 @@ interface NoteRoutesProps {
|
||||
note: GraphNode;
|
||||
noteId: number;
|
||||
notebook: Graph;
|
||||
contacts: Contacts;
|
||||
api: GlobalApi;
|
||||
association: Association;
|
||||
baseUrl?: string;
|
||||
|
@ -7,6 +7,7 @@ import { Contacts, Rolodex, Groups, Associations, Graph, Association, Unreads }
|
||||
import { NotebookPosts } from './NotebookPosts';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { useShowNickname } from '~/logic/lib/util';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
interface NotebookProps {
|
||||
api: GlobalApi;
|
||||
@ -15,7 +16,6 @@ interface NotebookProps {
|
||||
graph: Graph;
|
||||
association: Association;
|
||||
associations: Associations;
|
||||
contacts: Rolodex;
|
||||
groups: Groups;
|
||||
baseUrl: string;
|
||||
rootUrl: string;
|
||||
@ -26,7 +26,6 @@ export function Notebook(props: NotebookProps & RouteComponentProps): ReactEleme
|
||||
const {
|
||||
ship,
|
||||
book,
|
||||
contacts,
|
||||
groups,
|
||||
association,
|
||||
graph
|
||||
@ -38,6 +37,7 @@ export function Notebook(props: NotebookProps & RouteComponentProps): ReactEleme
|
||||
}
|
||||
|
||||
const relativePath = (p: string) => props.baseUrl + p;
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
|
||||
const contact = contacts?.[`~${ship}`];
|
||||
console.log(association.resource);
|
||||
@ -60,7 +60,6 @@ export function Notebook(props: NotebookProps & RouteComponentProps): ReactEleme
|
||||
graph={graph}
|
||||
host={ship}
|
||||
book={book}
|
||||
contacts={contacts}
|
||||
unreads={props.unreads}
|
||||
baseUrl={props.baseUrl}
|
||||
api={props.api}
|
||||
|
@ -2,9 +2,9 @@ import React, { Component } from 'react';
|
||||
import { Col } from '@tlon/indigo-react';
|
||||
import { NotePreview } from './NotePreview';
|
||||
import { Contacts, Graph, Unreads, Group } from '@urbit/api';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
interface NotebookPostsProps {
|
||||
contacts: Contacts;
|
||||
graph: Graph;
|
||||
host: string;
|
||||
book: string;
|
||||
@ -17,6 +17,7 @@ interface NotebookPostsProps {
|
||||
}
|
||||
|
||||
export function NotebookPosts(props: NotebookPostsProps) {
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
return (
|
||||
<Col>
|
||||
{Array.from(props.graph || []).map(
|
||||
@ -27,8 +28,7 @@ export function NotebookPosts(props: NotebookPostsProps) {
|
||||
host={props.host}
|
||||
book={props.book}
|
||||
unreads={props.unreads}
|
||||
contact={props.contacts[`~${node.post.author}`]}
|
||||
contacts={props.contacts}
|
||||
contact={contacts[`~${node.post.author}`]}
|
||||
node={node}
|
||||
baseUrl={props.baseUrl}
|
||||
api={props.api}
|
||||
|
@ -24,7 +24,6 @@ interface NotebookRoutesProps {
|
||||
book: string;
|
||||
graphs: Graphs;
|
||||
unreads: Unreads;
|
||||
contacts: Rolodex;
|
||||
groups: Groups;
|
||||
baseUrl: string;
|
||||
rootUrl: string;
|
||||
@ -36,7 +35,7 @@ interface NotebookRoutesProps {
|
||||
export function NotebookRoutes(
|
||||
props: NotebookRoutesProps & RouteComponentProps
|
||||
) {
|
||||
const { ship, book, api, contacts, baseUrl, rootUrl, groups } = props;
|
||||
const { ship, book, api, baseUrl, rootUrl, groups } = props;
|
||||
|
||||
useEffect(() => {
|
||||
ship && book && api.graph.getGraph(ship, book);
|
||||
@ -59,7 +58,6 @@ export function NotebookRoutes(
|
||||
return <Notebook
|
||||
{...props}
|
||||
graph={graph}
|
||||
contacts={contacts}
|
||||
association={props.association}
|
||||
rootUrl={rootUrl}
|
||||
baseUrl={baseUrl}
|
||||
@ -106,7 +104,6 @@ export function NotebookRoutes(
|
||||
notebook={graph}
|
||||
unreads={props.unreads}
|
||||
noteId={noteIdNum}
|
||||
contacts={contacts}
|
||||
association={props.association}
|
||||
group={group}
|
||||
s3={props.s3}
|
||||
|
@ -7,7 +7,7 @@ import { AsyncButton } from '~/views/components/AsyncButton';
|
||||
|
||||
export class Writers extends Component {
|
||||
render() {
|
||||
const { association, groups, contacts, api } = this.props;
|
||||
const { association, groups, api } = this.props;
|
||||
|
||||
const resource = resourceFromPath(association?.group);
|
||||
|
||||
@ -40,7 +40,6 @@ export class Writers extends Component {
|
||||
<Form>
|
||||
<ShipSearch
|
||||
groups={groups}
|
||||
contacts={contacts}
|
||||
id="ships"
|
||||
label=""
|
||||
maxLength={undefined}
|
||||
|
@ -11,9 +11,9 @@ import OverlaySigil from './OverlaySigil';
|
||||
import { Sigil } from '~/logic/lib/sigil';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import Timestamp from './Timestamp';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
interface AuthorProps {
|
||||
contacts: Contacts;
|
||||
ship: string;
|
||||
date: number;
|
||||
showImage?: boolean;
|
||||
@ -25,9 +25,10 @@ interface AuthorProps {
|
||||
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
export default function Author(props: AuthorProps): ReactElement {
|
||||
const { contacts, ship = '', date, showImage, group } = props;
|
||||
const { ship = '', date, showImage, group } = props;
|
||||
const history = useHistory();
|
||||
let contact;
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
if (contacts) {
|
||||
contact = `~${deSig(ship)}` in contacts ? contacts[`~${deSig(ship)}`] : null;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ interface CommentItemProps {
|
||||
pending?: boolean;
|
||||
comment: GraphNode;
|
||||
baseUrl: string;
|
||||
contacts: Contacts;
|
||||
unread: boolean;
|
||||
name: string;
|
||||
ship: string;
|
||||
@ -30,7 +29,7 @@ interface CommentItemProps {
|
||||
}
|
||||
|
||||
export function CommentItem(props: CommentItemProps): ReactElement {
|
||||
const { ship, contacts, name, api, comment, group } = props;
|
||||
const { ship, name, api, comment, group } = props;
|
||||
const [, post] = getLatestCommentRevision(comment);
|
||||
const disabled = props.pending || window.ship !== post?.author;
|
||||
|
||||
@ -47,7 +46,6 @@ export function CommentItem(props: CommentItemProps): ReactElement {
|
||||
<Row bg="white" my={3}>
|
||||
<Author
|
||||
showImage
|
||||
contacts={contacts}
|
||||
ship={post?.author}
|
||||
date={post?.['time-sent']}
|
||||
unread={props.unread}
|
||||
@ -73,7 +71,6 @@ export function CommentItem(props: CommentItemProps): ReactElement {
|
||||
</Row>
|
||||
<Box mb={2}>
|
||||
<MentionText
|
||||
contacts={contacts}
|
||||
group={group}
|
||||
content={post?.contents}
|
||||
/>
|
||||
|
@ -21,7 +21,6 @@ interface CommentsProps {
|
||||
ship: string;
|
||||
editCommentId: string;
|
||||
baseUrl: string;
|
||||
contacts: Contacts;
|
||||
api: GlobalApi;
|
||||
group: Group;
|
||||
}
|
||||
@ -130,7 +129,6 @@ export function Comments(props: CommentsProps & PropFunc<typeof Col>) {
|
||||
<CommentItem
|
||||
comment={comment}
|
||||
key={idx.toString()}
|
||||
contacts={props.contacts}
|
||||
api={api}
|
||||
name={name}
|
||||
ship={ship}
|
||||
|
@ -29,7 +29,6 @@ interface InviteItemProps {
|
||||
app?: string;
|
||||
uid?: string;
|
||||
api: GlobalApi;
|
||||
contacts: Contacts;
|
||||
}
|
||||
|
||||
export function InviteItem(props: InviteItemProps) {
|
||||
|
@ -6,18 +6,18 @@ import RichText from '~/views/components/RichText';
|
||||
import { cite, useShowNickname, uxToHex } from '~/logic/lib/util';
|
||||
import OverlaySigil from '~/views/components/OverlaySigil';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
interface MentionTextProps {
|
||||
contact?: Contact;
|
||||
contacts?: Contacts;
|
||||
content: Content[];
|
||||
group: Group;
|
||||
}
|
||||
export function MentionText(props: MentionTextProps) {
|
||||
const { content, contacts, contact, group, ...rest } = props;
|
||||
const { content, contact, group, ...rest } = props;
|
||||
|
||||
return (
|
||||
<RichText contacts={contacts} contact={contact} group={group} {...rest}>
|
||||
<RichText contact={contact} group={group} {...rest}>
|
||||
{content.reduce((accum, c) => {
|
||||
if ('text' in c) {
|
||||
return accum + c.text;
|
||||
@ -34,14 +34,14 @@ export function MentionText(props: MentionTextProps) {
|
||||
|
||||
export function Mention(props: {
|
||||
contact: Contact;
|
||||
contacts?: Contacts;
|
||||
group: Group;
|
||||
scrollWindow?: HTMLElement;
|
||||
ship: string;
|
||||
first?: Boolean;
|
||||
}) {
|
||||
const { contacts, ship, scrollWindow, first, ...rest } = props;
|
||||
const { ship, scrollWindow, first, ...rest } = props;
|
||||
let { contact } = props;
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
contact = contact?.color ? contact : contacts?.[ship];
|
||||
const history = useHistory();
|
||||
const showNickname = useShowNickname(contact);
|
||||
|
@ -42,7 +42,7 @@ const RichText = React.memo(({ disableRemoteContent, ...props }) => (
|
||||
linkReference: (linkProps) => {
|
||||
const linkText = String(linkProps.children[0].props.children);
|
||||
if (isValidPatp(linkText)) {
|
||||
return <Mention contacts={props.contacts || {}} contact={props.contact || {}} group={props.group} ship={deSig(linkText)} />;
|
||||
return <Mention contact={props.contact || {}} group={props.group} ship={deSig(linkText)} />;
|
||||
}
|
||||
return linkText;
|
||||
},
|
||||
|
@ -24,6 +24,7 @@ import { Rolodex, Groups } from '@urbit/api';
|
||||
import { DropdownSearch } from './DropdownSearch';
|
||||
import { cite, deSig } from '~/logic/lib/util';
|
||||
import { HoverBox } from './HoverBox';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
interface InviteSearchProps<I extends string> {
|
||||
autoFocus?: boolean;
|
||||
@ -121,9 +122,11 @@ export function ShipSearch<I extends string, V extends Value<I>>(
|
||||
|
||||
const pills = selected.slice(0, inputIdx.current);
|
||||
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
|
||||
const [peers, nicknames] = useMemo(
|
||||
() => getNicknameForShips(props.groups, props.contacts),
|
||||
[props.contacts, props.groups]
|
||||
() => getNicknameForShips(props.groups, contacts),
|
||||
[contacts, props.groups]
|
||||
);
|
||||
|
||||
const renderCandidate = useCallback(
|
||||
|
@ -16,10 +16,10 @@ import defaultApps from '~/logic/lib/default-apps';
|
||||
import { useOutsideClick } from '~/logic/lib/useOutsideClick';
|
||||
import { Portal } from '../Portal';
|
||||
import { Tile } from '~/types';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
interface OmniboxProps {
|
||||
associations: Associations;
|
||||
contacts: Contacts;
|
||||
groups: Groups;
|
||||
tiles: {
|
||||
[app: string]: Tile;
|
||||
@ -40,13 +40,14 @@ export function Omnibox(props: OmniboxProps) {
|
||||
|
||||
const [query, setQuery] = useState('');
|
||||
const [selected, setSelected] = useState<[] | [string, string]>([]);
|
||||
const contactState = useContactState(state => state.contacts);
|
||||
|
||||
const contacts = useMemo(() => {
|
||||
const maybeShip = `~${deSig(query)}`;
|
||||
return ob.isValidPatp(maybeShip)
|
||||
? { ...props.contacts, [maybeShip]: {} }
|
||||
: props.contacts;
|
||||
}, [props.contacts, query]);
|
||||
? { ...contactState, [maybeShip]: {} }
|
||||
: contactState;
|
||||
}, [contactState, query]);
|
||||
|
||||
const index = useMemo(() => {
|
||||
const selectedGroup = location.pathname.startsWith('/~landscape/ship/')
|
||||
@ -257,7 +258,6 @@ export function Omnibox(props: OmniboxProps) {
|
||||
selected={sel}
|
||||
invites={props.invites}
|
||||
notifications={props.notifications}
|
||||
contacts={props.contacts}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
@ -265,7 +265,7 @@ export function Omnibox(props: OmniboxProps) {
|
||||
})
|
||||
}
|
||||
</Box>;
|
||||
}, [results, navigate, selected, props.contacts, props.notifications, props.invites]);
|
||||
}, [results, navigate, selected, contactState, props.notifications, props.invites]);
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
|
@ -177,7 +177,7 @@ export function GraphPermissions(props: GraphPermissionsProps) {
|
||||
vip={association.metadata.vip}
|
||||
/>
|
||||
</Col>
|
||||
<ChannelWritePerms contacts={props.contacts} groups={props.groups} />
|
||||
<ChannelWritePerms groups={props.groups} />
|
||||
{association.metadata.module !== 'chat' && (
|
||||
<Checkbox
|
||||
id="readerComments"
|
||||
|
@ -34,7 +34,6 @@ export function ChannelWritePerms<
|
||||
{values.writePerms === 'subset' && (
|
||||
<ShipSearch
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
id="writers"
|
||||
label=""
|
||||
maxLength={undefined}
|
||||
|
@ -27,6 +27,7 @@ import '~/views/apps/publish/css/custom.css';
|
||||
import { getGroupFromWorkspace } from '~/logic/lib/workspace';
|
||||
import { GroupSummary } from './GroupSummary';
|
||||
import { Workspace } from '~/types/workspace';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
type GroupsPaneProps = StoreState & {
|
||||
baseUrl: string;
|
||||
@ -35,7 +36,8 @@ type GroupsPaneProps = StoreState & {
|
||||
};
|
||||
|
||||
export function GroupsPane(props: GroupsPaneProps) {
|
||||
const { baseUrl, associations, groups, contacts, api, workspace } = props;
|
||||
const { baseUrl, associations, groups, api, workspace } = props;
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
const relativePath = (path: string) => baseUrl + path;
|
||||
const groupPath = getGroupFromWorkspace(workspace);
|
||||
|
||||
@ -82,7 +84,6 @@ export function GroupsPane(props: GroupsPaneProps) {
|
||||
association={groupAssociation!}
|
||||
baseUrl={baseUrl}
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
workspace={workspace}
|
||||
/>
|
||||
</>
|
||||
@ -181,7 +182,6 @@ export function GroupsPane(props: GroupsPaneProps) {
|
||||
associations={associations}
|
||||
groups={groups}
|
||||
group={groupPath}
|
||||
contacts={props.contacts}
|
||||
workspace={workspace}
|
||||
/>
|
||||
{popovers(routeProps, baseUrl)}
|
||||
|
@ -115,7 +115,6 @@ export function InvitePopover(props: InvitePopoverProps) {
|
||||
</Box>
|
||||
<ShipSearch
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
id="ships"
|
||||
label=""
|
||||
autoFocus
|
||||
|
@ -178,13 +178,11 @@ export function NewChannel(props: NewChannelProps & RouteComponentProps): ReactE
|
||||
{(workspace?.type === 'home' || workspace?.type === 'messages') ? (
|
||||
<ShipSearch
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
id="ships"
|
||||
label="Invitees"
|
||||
/>) : (
|
||||
<ChannelWritePerms
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
/>
|
||||
)}
|
||||
<Box justifySelf="start">
|
||||
|
@ -30,6 +30,7 @@ import { Dropdown } from '~/views/components/Dropdown';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
|
||||
import useLocalState from '~/logic/state/local';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
const TruncText = styled(Text)`
|
||||
white-space: nowrap;
|
||||
@ -103,7 +104,6 @@ const Tab = ({ selected, id, label, setSelected }) => (
|
||||
);
|
||||
|
||||
export function Participants(props: {
|
||||
contacts: Contacts;
|
||||
group: Group;
|
||||
association: Association;
|
||||
api: GlobalApi;
|
||||
@ -136,9 +136,10 @@ export function Participants(props: {
|
||||
|
||||
const adminCount = props.group.tags?.role?.admin?.size || 0;
|
||||
const isInvite = 'invite' in props.group.policy;
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
|
||||
const [participants, pendingCount, memberCount] = getParticipants(
|
||||
props.contacts,
|
||||
contacts,
|
||||
props.group
|
||||
);
|
||||
|
||||
|
@ -20,7 +20,6 @@ import { S3State } from '~/types';
|
||||
export function PopoverRoutes(
|
||||
props: {
|
||||
baseUrl: string;
|
||||
contacts: Contacts;
|
||||
group: Group;
|
||||
association: Association;
|
||||
associations: Associations;
|
||||
@ -134,7 +133,6 @@ export function PopoverRoutes(
|
||||
{view === 'participants' && (
|
||||
<Participants
|
||||
group={props.group}
|
||||
contacts={props.contacts}
|
||||
association={props.association}
|
||||
api={props.api}
|
||||
/>
|
||||
|
@ -58,7 +58,6 @@ export function Resource(props: ResourceProps): ReactElement {
|
||||
association={association}
|
||||
group={props.groups?.[selectedGroup]}
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
api={props.api}
|
||||
baseUrl={relativePath('')}
|
||||
rootUrl={props.baseUrl}
|
||||
|
@ -11,6 +11,7 @@ import RichText from '~/views/components/RichText';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { isWriter } from '~/logic/lib/group';
|
||||
import { getItemTitle } from '~/logic/lib/util';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
const TruncatedBox = styled(Box)`
|
||||
white-space: pre;
|
||||
@ -48,9 +49,11 @@ export function ResourceSkeleton(props: ResourceSkeletonProps): ReactElement {
|
||||
|
||||
let recipient = false;
|
||||
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
|
||||
if (urbitOb.isValidPatp(title)) {
|
||||
recipient = title;
|
||||
title = (props.contacts?.[title]?.nickname) ? props.contacts[title].nickname : title;
|
||||
title = (contacts?.[title]?.nickname) ? contacts[title].nickname : title;
|
||||
}
|
||||
|
||||
const [, , ship, resource] = rid.split('/');
|
||||
|
@ -91,7 +91,6 @@ export function Sidebar(props: SidebarProps): ReactElement {
|
||||
/>
|
||||
<SidebarListHeader
|
||||
associations={associations}
|
||||
contacts={props.contacts}
|
||||
baseUrl={props.baseUrl}
|
||||
groups={props.groups}
|
||||
initialValues={config}
|
||||
@ -110,7 +109,6 @@ export function Sidebar(props: SidebarProps): ReactElement {
|
||||
apps={props.apps}
|
||||
baseUrl={props.baseUrl}
|
||||
workspace={workspace}
|
||||
contacts={props.contacts}
|
||||
/>
|
||||
</ScrollbarLessCol>
|
||||
);
|
||||
|
@ -12,6 +12,7 @@ import useLocalState from '~/logic/state/local';
|
||||
import { TUTORIAL_HOST, TUTORIAL_GROUP } from '~/logic/lib/tutorialModal';
|
||||
import { SidebarAppConfigs, SidebarItemStatus } from './types';
|
||||
import { Workspace } from '~/types/workspace';
|
||||
import useContactState from '~/logic/state/contacts';
|
||||
|
||||
function SidebarItemIndicator(props: { status?: SidebarItemStatus }) {
|
||||
switch (props.status) {
|
||||
@ -84,14 +85,16 @@ export function SidebarItem(props: {
|
||||
|
||||
let img = null;
|
||||
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
|
||||
if (urbitOb.isValidPatp(title)) {
|
||||
if (props.contacts?.[title]?.avatar && !hideAvatars) {
|
||||
img = <BaseImage src={props.contacts[title].avatar} width='16px' height='16px' borderRadius={2} />;
|
||||
if (contacts?.[title]?.avatar && !hideAvatars) {
|
||||
img = <BaseImage src={contacts[title].avatar} width='16px' height='16px' borderRadius={2} />;
|
||||
} else {
|
||||
img = <Sigil ship={title} color={`#${uxToHex(props.contacts?.[title]?.color || '0x0')}`} icon padding={2} size={16} />;
|
||||
img = <Sigil ship={title} color={`#${uxToHex(contacts?.[title]?.color || '0x0')}`} icon padding={2} size={16} />;
|
||||
}
|
||||
if (props.contacts?.[title]?.nickname && !hideNicknames) {
|
||||
title = props.contacts[title].nickname;
|
||||
if (contacts?.[title]?.nickname && !hideNicknames) {
|
||||
title = contacts[title].nickname;
|
||||
}
|
||||
} else {
|
||||
img = <Box flexShrink={0} height={16} width={16} borderRadius={2} backgroundColor={`#${uxToHex(props?.association?.metadata?.color)}` || '#000000'} />;
|
||||
|
@ -77,7 +77,6 @@ export function SidebarList(props: {
|
||||
apps={props.apps}
|
||||
hideUnjoined={config.hideUnjoined}
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
workspace={workspace}
|
||||
/>
|
||||
);
|
||||
|
@ -87,7 +87,6 @@ export function SidebarListHeader(props: {
|
||||
api={props.api}
|
||||
history={props.history}
|
||||
associations={props.associations}
|
||||
contacts={props.contacts}
|
||||
groups={props.groups}
|
||||
workspace={props.workspace}
|
||||
/>
|
||||
|
@ -49,7 +49,6 @@ export function Skeleton(props: SkeletonProps): ReactElement {
|
||||
gridTemplateRows="100%"
|
||||
>
|
||||
<Sidebar
|
||||
contacts={props.contacts}
|
||||
api={props.api}
|
||||
recentGroups={props.recentGroups}
|
||||
selected={props.selected}
|
||||
|
@ -117,7 +117,6 @@ export default class Landscape extends Component<LandscapeProps, Record<string,
|
||||
<NewGroup
|
||||
associations={props.associations}
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
api={props.api}
|
||||
{...routeProps}
|
||||
/>
|
||||
@ -141,7 +140,6 @@ export default class Landscape extends Component<LandscapeProps, Record<string,
|
||||
<Box maxWidth="300px">
|
||||
<JoinGroup
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
api={props.api}
|
||||
autojoin={autojoin}
|
||||
{...routeProps}
|
||||
|
Loading…
Reference in New Issue
Block a user