mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-01 03:23:09 +03:00
interface: fix misc bugs
This commit is contained in:
parent
a49399269b
commit
d593561b0f
@ -18,11 +18,11 @@
|
|||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"background_color": "%23FFFFFF",
|
"background_color": "%23FFFFFF",
|
||||||
"theme_color": "%23000000"}' />
|
"theme_color": "%23000000"}' />
|
||||||
|
<script src="/apps/landscape/desk.js"></script>
|
||||||
|
<script src="/session.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<div id="portal-root"></div>
|
<div id="portal-root"></div>
|
||||||
<script src="/apps/landscape/desk.js"></script>
|
|
||||||
<script src="/session.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -107,7 +107,7 @@ function updateNotificationStats(state: HarkState, place: HarkPlace, f: (s: Hark
|
|||||||
}
|
}
|
||||||
|
|
||||||
function seenIndex(json: any, state: HarkState): HarkState {
|
function seenIndex(json: any, state: HarkState): HarkState {
|
||||||
const data = _.get(json, 'seen-index');
|
const data = _.get(json, 'saw-place');
|
||||||
if(data) {
|
if(data) {
|
||||||
updateNotificationStats(state, data, s => ({ last: Date.now() }));
|
updateNotificationStats(state, data, s => ({ last: Date.now() }));
|
||||||
}
|
}
|
||||||
@ -154,6 +154,7 @@ function unreadEach(json: any, state: HarkState): HarkState {
|
|||||||
function allStats(json: any, state: HarkState): HarkState {
|
function allStats(json: any, state: HarkState): HarkState {
|
||||||
if('all-stats' in json) {
|
if('all-stats' in json) {
|
||||||
const data = json['all-stats'];
|
const data = json['all-stats'];
|
||||||
|
console.log(data);
|
||||||
data.forEach(({ place, stats }) => {
|
data.forEach(({ place, stats }) => {
|
||||||
state.unreads[place.path] = stats;
|
state.unreads[place.path] = stats;
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,6 @@ import {
|
|||||||
markCountAsRead,
|
markCountAsRead,
|
||||||
Notification,
|
Notification,
|
||||||
NotificationGraphConfig,
|
NotificationGraphConfig,
|
||||||
readNote,
|
|
||||||
Unreads
|
Unreads
|
||||||
} from '@urbit/api';
|
} from '@urbit/api';
|
||||||
import { Poke } from '@urbit/http-api';
|
import { Poke } from '@urbit/http-api';
|
||||||
@ -132,9 +131,8 @@ export function useHarkDm(ship: string) {
|
|||||||
return useHarkState(
|
return useHarkState(
|
||||||
useCallback(
|
useCallback(
|
||||||
(s) => {
|
(s) => {
|
||||||
return s.unreads[`/graph/~${window.ship}/dm-inbox`]?.[
|
const key = `/graph/~${window.ship}/dm-inbox/${patp2dec(ship)}`;
|
||||||
`/${patp2dec(ship)}`
|
return s.unreads[key] || emptyStats();
|
||||||
] || emptyStats();
|
|
||||||
},
|
},
|
||||||
[ship]
|
[ship]
|
||||||
)
|
)
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
import React, { useState, useEffect, useCallback } from "react";
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
import { useHistory, useParams } from "react-router-dom";
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Col,
|
Col,
|
||||||
Row,
|
Row,
|
||||||
Text,
|
Text,
|
||||||
Button,
|
|
||||||
Action,
|
Action,
|
||||||
LoadingSpinner,
|
LoadingSpinner
|
||||||
} from "@tlon/indigo-react";
|
} from '@tlon/indigo-react';
|
||||||
import * as Dialog from "@radix-ui/react-dialog";
|
import * as Dialog from '@radix-ui/react-dialog';
|
||||||
import { PropFunc } from "~/types";
|
import { PropFunc } from '~/types';
|
||||||
import { useRunIO } from "~/logic/lib/useRunIO";
|
import { useRunIO } from '~/logic/lib/useRunIO';
|
||||||
import useMetadataState from "~/logic/state/metadata";
|
import useMetadataState from '~/logic/state/metadata';
|
||||||
import { GroupSummary } from "~/views/landscape/components/GroupSummary";
|
import { GroupSummary } from '~/views/landscape/components/GroupSummary';
|
||||||
import {
|
import {
|
||||||
accept,
|
accept,
|
||||||
decline,
|
decline,
|
||||||
@ -22,13 +21,13 @@ import {
|
|||||||
join,
|
join,
|
||||||
Metadata,
|
Metadata,
|
||||||
MetadataUpdatePreview,
|
MetadataUpdatePreview,
|
||||||
resourceFromPath,
|
resourceFromPath
|
||||||
} from "@urbit/api";
|
} from '@urbit/api';
|
||||||
import useInviteState from "~/logic/state/invite";
|
import useInviteState from '~/logic/state/invite';
|
||||||
import useGroupState from "~/logic/state/group";
|
import useGroupState from '~/logic/state/group';
|
||||||
import useGraphState from "~/logic/state/graph";
|
import useGraphState from '~/logic/state/graph';
|
||||||
import { useWaitForProps } from "~/logic/lib/useWaitForProps";
|
import { useWaitForProps } from '~/logic/lib/useWaitForProps';
|
||||||
import airlock from "~/logic/api";
|
import airlock from '~/logic/api';
|
||||||
|
|
||||||
function InviteDialog({ children, ...rest }: PropFunc<typeof Col>) {
|
function InviteDialog({ children, ...rest }: PropFunc<typeof Col>) {
|
||||||
return (
|
return (
|
||||||
@ -84,7 +83,7 @@ function inviteUrl(
|
|||||||
return `/~landscape${resource}`;
|
return `/~landscape${resource}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata.config?.graph === "chat") {
|
if (metadata.config?.graph === 'chat') {
|
||||||
return `/~landscape/messages/resource/${metadata.config.graph}${resource}`;
|
return `/~landscape/messages/resource/${metadata.config.graph}${resource}`;
|
||||||
} else {
|
} else {
|
||||||
return `/~landscape/home/resource/${metadata.config?.graph}${resource}`;
|
return `/~landscape/home/resource/${metadata.config?.graph}${resource}`;
|
||||||
@ -94,9 +93,9 @@ function inviteUrl(
|
|||||||
function useInviteAccept(resource: string, app?: string, uid?: string) {
|
function useInviteAccept(resource: string, app?: string, uid?: string) {
|
||||||
const { ship, name } = resourceFromPath(resource);
|
const { ship, name } = resourceFromPath(resource);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const associations = useMetadataState((s) => s.associations);
|
const associations = useMetadataState(s => s.associations);
|
||||||
const groups = useGroupState((s) => s.groups);
|
const groups = useGroupState(s => s.groups);
|
||||||
const graphKeys = useGraphState((s) => s.graphKeys);
|
const graphKeys = useGraphState(s => s.graphKeys);
|
||||||
|
|
||||||
const waiter = useWaitForProps({ associations, graphKeys, groups });
|
const waiter = useWaitForProps({ associations, graphKeys, groups });
|
||||||
return useRunIO<void, boolean>(
|
return useRunIO<void, boolean>(
|
||||||
@ -110,7 +109,6 @@ function useInviteAccept(resource: string, app?: string, uid?: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await airlock.poke(join(ship, name));
|
await airlock.poke(join(ship, name));
|
||||||
await airlock.poke(accept(app, uid));
|
|
||||||
await waiter((p) => {
|
await waiter((p) => {
|
||||||
return (
|
return (
|
||||||
(resource in p.groups &&
|
(resource in p.groups &&
|
||||||
@ -119,10 +117,12 @@ function useInviteAccept(resource: string, app?: string, uid?: string) {
|
|||||||
resource in (p.associations?.groups ?? {})
|
resource in (p.associations?.groups ?? {})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
airlock.poke(accept(app, uid));
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
(success: boolean) => {
|
(success: boolean) => {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
history.push('/');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const redir = inviteUrl(
|
const redir = inviteUrl(
|
||||||
@ -147,11 +147,11 @@ export function Invite() {
|
|||||||
uid: string;
|
uid: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const invite = useInviteState((s) => s.invites?.[app]?.[uid]);
|
const invite = useInviteState(s => s.invites?.[app]?.[uid]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InviteDialog>
|
<InviteDialog>
|
||||||
{!!invite ? (
|
{invite ? (
|
||||||
<>
|
<>
|
||||||
{renderInviteContent(app, uid, invite)}
|
{renderInviteContent(app, uid, invite)}
|
||||||
<InviteActions app={app} uid={uid} invite={invite} />
|
<InviteActions app={app} uid={uid} invite={invite} />
|
||||||
@ -166,7 +166,7 @@ export function Invite() {
|
|||||||
function InviteActions({
|
function InviteActions({
|
||||||
app,
|
app,
|
||||||
uid,
|
uid,
|
||||||
invite,
|
invite
|
||||||
}: {
|
}: {
|
||||||
app: string;
|
app: string;
|
||||||
uid: string;
|
uid: string;
|
||||||
@ -201,9 +201,9 @@ function InviteActions({
|
|||||||
|
|
||||||
function GroupInvite({ uid, invite }: { uid: string; invite: IInvite }) {
|
function GroupInvite({ uid, invite }: { uid: string; invite: IInvite }) {
|
||||||
const {
|
const {
|
||||||
resource: { ship, name },
|
resource: { ship, name }
|
||||||
} = invite;
|
} = invite;
|
||||||
const { associations, getPreview } = useMetadataState();
|
const { getPreview } = useMetadataState();
|
||||||
const [preview, setPreview] = useState<MetadataUpdatePreview | null>(null);
|
const [preview, setPreview] = useState<MetadataUpdatePreview | null>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
@ -218,8 +218,8 @@ function GroupInvite({ uid, invite }: { uid: string; invite: IInvite }) {
|
|||||||
return preview ? (
|
return preview ? (
|
||||||
<GroupSummary
|
<GroupSummary
|
||||||
metadata={preview.metadata}
|
metadata={preview.metadata}
|
||||||
channelCount={preview["channel-count"]}
|
channelCount={preview['channel-count']}
|
||||||
memberCount={preview["members"]}
|
memberCount={preview['members']}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
@ -232,9 +232,9 @@ function GraphInvite({ uid, invite }: { uid: string; invite: IInvite }) {
|
|||||||
|
|
||||||
function renderInviteContent(app: string, uid: string, invite: IInvite) {
|
function renderInviteContent(app: string, uid: string, invite: IInvite) {
|
||||||
switch (app) {
|
switch (app) {
|
||||||
case "groups":
|
case 'groups':
|
||||||
return <GroupInvite uid={uid} invite={invite} />;
|
return <GroupInvite uid={uid} invite={invite} />;
|
||||||
case "graph":
|
case 'graph':
|
||||||
return <GraphInvite uid={uid} invite={invite} />;
|
return <GraphInvite uid={uid} invite={invite} />;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
@ -8,13 +8,10 @@ import {
|
|||||||
Text
|
Text
|
||||||
} from '@tlon/indigo-react';
|
} from '@tlon/indigo-react';
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { Link, useHistory } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Sigil } from '~/logic/lib/sigil';
|
import { Sigil } from '~/logic/lib/sigil';
|
||||||
import { uxToHex } from '~/logic/lib/util';
|
import { uxToHex } from '~/logic/lib/util';
|
||||||
import useContactState from '~/logic/state/contact';
|
import useContactState from '~/logic/state/contact';
|
||||||
import useHarkState from '~/logic/state/hark';
|
|
||||||
import useLaunchState from '~/logic/state/launch';
|
|
||||||
import useInviteState from '~/logic/state/invite';
|
|
||||||
import useLocalState, { selectLocalState } from '~/logic/state/local';
|
import useLocalState, { selectLocalState } from '~/logic/state/local';
|
||||||
import useSettingsState, { selectCalmState } from '~/logic/state/settings';
|
import useSettingsState, { selectCalmState } from '~/logic/state/settings';
|
||||||
import { Dropdown } from './Dropdown';
|
import { Dropdown } from './Dropdown';
|
||||||
@ -22,21 +19,13 @@ import { ProfileStatus } from './ProfileStatus';
|
|||||||
import ReconnectButton from './ReconnectButton';
|
import ReconnectButton from './ReconnectButton';
|
||||||
import { StatusBarItem } from './StatusBarItem';
|
import { StatusBarItem } from './StatusBarItem';
|
||||||
import { useTutorialModal } from './useTutorialModal';
|
import { useTutorialModal } from './useTutorialModal';
|
||||||
import {StatusBarJoins} from './StatusBarJoins';
|
import { StatusBarJoins } from './StatusBarJoins';
|
||||||
|
|
||||||
const localSel = selectLocalState(['toggleOmnibox']);
|
const localSel = selectLocalState(['toggleOmnibox']);
|
||||||
|
|
||||||
const StatusBar = (props) => {
|
const StatusBar = (props) => {
|
||||||
const { ship } = props;
|
const { ship } = props;
|
||||||
const history = useHistory();
|
|
||||||
const runtimeLag = useLaunchState(state => state.runtimeLag);
|
|
||||||
const ourContact = useContactState(state => state.contacts[`~${ship}`]);
|
const ourContact = useContactState(state => state.contacts[`~${ship}`]);
|
||||||
const notificationsCount = useHarkState(state => state.notificationsCount);
|
|
||||||
const doNotDisturb = useHarkState(state => state.doNotDisturb);
|
|
||||||
const inviteState = useInviteState(state => state.invites);
|
|
||||||
const invites = [].concat(
|
|
||||||
...Object.values(inviteState).map(obj => Object.values(obj))
|
|
||||||
);
|
|
||||||
const metaKey = window.navigator.platform.includes('Mac') ? '⌘' : 'Ctrl+';
|
const metaKey = window.navigator.platform.includes('Mac') ? '⌘' : 'Ctrl+';
|
||||||
const { toggleOmnibox } = useLocalState(localSel);
|
const { toggleOmnibox } = useLocalState(localSel);
|
||||||
const { hideAvatars } = useSettingsState(selectCalmState);
|
const { hideAvatars } = useSettingsState(selectCalmState);
|
||||||
@ -87,16 +76,6 @@ const StatusBar = (props) => {
|
|||||||
<Icon icon='Dashboard' color='black' />
|
<Icon icon='Dashboard' color='black' />
|
||||||
</Button>
|
</Button>
|
||||||
<StatusBarItem float={floatLeap} mr={2} onClick={() => toggleOmnibox()}>
|
<StatusBarItem float={floatLeap} mr={2} onClick={() => toggleOmnibox()}>
|
||||||
{!doNotDisturb && runtimeLag && (
|
|
||||||
<Box display='block' right='-8px' top='-8px' position='absolute'>
|
|
||||||
<Icon color='yellow' icon='Bullet' />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{!doNotDisturb && (notificationsCount > 0 || invites.length > 0) && (
|
|
||||||
<Box display='block' right='-8px' top='-8px' position='absolute'>
|
|
||||||
<Icon color='blue' icon='Bullet' />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
<Icon icon='LeapArrow' />
|
<Icon icon='LeapArrow' />
|
||||||
<Text ref={anchorRef} ml={2} color='black'>
|
<Text ref={anchorRef} ml={2} color='black'>
|
||||||
Leap
|
Leap
|
||||||
|
@ -119,7 +119,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
|||||||
if (category === 'other') {
|
if (category === 'other') {
|
||||||
return [
|
return [
|
||||||
'other',
|
'other',
|
||||||
index.get('other').filter(({ app }) => app !== 'tutorial')
|
index.get('other').filter(({ app }) => app !== 'tutorial' && app !== 'inbox')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return [category, []];
|
return [category, []];
|
||||||
|
@ -7,8 +7,6 @@ import { cite, uxToHex } from '~/logic/lib/util';
|
|||||||
import { IconRef } from '~/types/util';
|
import { IconRef } from '~/types/util';
|
||||||
import withState from '~/logic/lib/withState';
|
import withState from '~/logic/lib/withState';
|
||||||
import useContactState from '~/logic/state/contact';
|
import useContactState from '~/logic/state/contact';
|
||||||
import useHarkState from '~/logic/state/hark';
|
|
||||||
import useLaunchState from '~/logic/state/launch';
|
|
||||||
import useInviteState from '~/logic/state/invite';
|
import useInviteState from '~/logic/state/invite';
|
||||||
|
|
||||||
function OmniboxResultChord(props: {
|
function OmniboxResultChord(props: {
|
||||||
@ -34,8 +32,6 @@ interface OmniboxResultProps {
|
|||||||
invites: Invites;
|
invites: Invites;
|
||||||
link: string;
|
link: string;
|
||||||
navigate: () => void;
|
navigate: () => void;
|
||||||
notificationsCount: number;
|
|
||||||
runtimeLag: any;
|
|
||||||
selected: string;
|
selected: string;
|
||||||
setSelection: () => void;
|
setSelection: () => void;
|
||||||
subtext: string;
|
subtext: string;
|
||||||
@ -80,21 +76,11 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
|
|||||||
icon: string,
|
icon: string,
|
||||||
selected: string,
|
selected: string,
|
||||||
link: string,
|
link: string,
|
||||||
invites: Invites,
|
|
||||||
lag: any,
|
|
||||||
notificationsCount: number,
|
|
||||||
text: string,
|
text: string,
|
||||||
color: string
|
color: string
|
||||||
): (any) {
|
): (any) {
|
||||||
const iconFill =
|
const iconFill =
|
||||||
(this.state.hovered || selected === link) ? 'white' : 'black';
|
(this.state.hovered || selected === link) ? 'white' : 'black';
|
||||||
const bulletFill =
|
|
||||||
(this.state.hovered || selected === link) ? 'white' : 'blue';
|
|
||||||
const lagFill =
|
|
||||||
this.state.hovered || selected === link ? 'white' : 'yellow';
|
|
||||||
const inviteCount = [].concat(
|
|
||||||
...Object.values(invites).map(obj => Object.values(obj))
|
|
||||||
);
|
|
||||||
|
|
||||||
let graphic: ReactElement = <div />;
|
let graphic: ReactElement = <div />;
|
||||||
if (
|
if (
|
||||||
@ -120,35 +106,6 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
|
|||||||
color={iconFill}
|
color={iconFill}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (icon === 'inbox') {
|
|
||||||
graphic = (
|
|
||||||
<Box display='flex' verticalAlign='middle' position='relative'>
|
|
||||||
<Icon
|
|
||||||
display='inline-block'
|
|
||||||
verticalAlign='middle'
|
|
||||||
icon='Notifications'
|
|
||||||
mr={2}
|
|
||||||
size='18px'
|
|
||||||
color={iconFill}
|
|
||||||
/>
|
|
||||||
{lag && (
|
|
||||||
<Icon
|
|
||||||
display='inline-block'
|
|
||||||
icon='Bullet'
|
|
||||||
style={{ position: 'absolute', top: -5, left: 5 }}
|
|
||||||
color={lagFill}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{(notificationsCount > 0 || inviteCount.length > 0) && (
|
|
||||||
<Icon
|
|
||||||
display='inline-block'
|
|
||||||
icon='Bullet'
|
|
||||||
style={{ position: 'absolute', top: -5, left: 5 }}
|
|
||||||
color={bulletFill}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
} else if (icon === 'logout') {
|
} else if (icon === 'logout') {
|
||||||
graphic = (
|
graphic = (
|
||||||
<Icon
|
<Icon
|
||||||
@ -245,9 +202,6 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
|
|||||||
cursor,
|
cursor,
|
||||||
navigate,
|
navigate,
|
||||||
selected,
|
selected,
|
||||||
invites,
|
|
||||||
notificationsCount,
|
|
||||||
runtimeLag,
|
|
||||||
contacts,
|
contacts,
|
||||||
setSelection,
|
setSelection,
|
||||||
shiftDescription,
|
shiftDescription,
|
||||||
@ -262,9 +216,6 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
|
|||||||
icon,
|
icon,
|
||||||
selected,
|
selected,
|
||||||
link,
|
link,
|
||||||
invites,
|
|
||||||
runtimeLag,
|
|
||||||
notificationsCount,
|
|
||||||
text,
|
text,
|
||||||
color
|
color
|
||||||
);
|
);
|
||||||
@ -334,8 +285,6 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default withState(OmniboxResult, [
|
export default withState(OmniboxResult, [
|
||||||
[useLaunchState, ['runtimeLag']],
|
|
||||||
[useInviteState],
|
[useInviteState],
|
||||||
[useHarkState, ['notificationsCount']],
|
|
||||||
[useContactState]
|
[useContactState]
|
||||||
]);
|
]);
|
||||||
|
@ -108,7 +108,7 @@ export const Content = (props) => {
|
|||||||
if(Object.keys(associations).length > 0 && query.has('grid-note')) {
|
if(Object.keys(associations).length > 0 && query.has('grid-note')) {
|
||||||
history.push(getNotificationRedirect(query.get('grid-note')));
|
history.push(getNotificationRedirect(query.get('grid-note')));
|
||||||
}
|
}
|
||||||
}, [location.search]);
|
}, [location.search, associations]);
|
||||||
|
|
||||||
useShortcut('navForward', useCallback((e) => {
|
useShortcut('navForward', useCallback((e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -128,7 +128,8 @@ export const SidebarDmItem = React.memo((props: {
|
|||||||
!hideNicknames && contact?.nickname
|
!hideNicknames && contact?.nickname
|
||||||
? contact?.nickname
|
? contact?.nickname
|
||||||
: cite(ship) ?? ship;
|
: cite(ship) ?? ship;
|
||||||
const { unreads } = useHarkDm(ship) || { unreads: 0 };
|
const { count, each } = useHarkDm(ship);
|
||||||
|
const unreads = count + each.length;
|
||||||
const img =
|
const img =
|
||||||
contact?.avatar && !hideAvatars ? (
|
contact?.avatar && !hideAvatars ? (
|
||||||
<BaseImage
|
<BaseImage
|
||||||
|
Loading…
Reference in New Issue
Block a user