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