Skip to content

Commit

Permalink
UI Fixes and extensions (#423)
Browse files Browse the repository at this point in the history
* Fixed pagemeta responsiveness;

* Moved pagemeta;

* Cleared out old DemoData stuff;

* Moved necessary helper;

* Cleaned up emoji-picker;

* Cleaned up connect-info hooks to fetch as little as possible;

* Added contact image to cache; Migrated owner-app query cache to indexedDb;

* Unified contact name & image to always prefer local overrides;

* Using the contact name & image as much as possible; Adding updates to the contact on your drive much faster;

* Cleaned up the fallbackImage to use the svg as a base to avoid needing a custom size;

* More permission keys for mail app to actually update the contact;

* Added 'contact' to all offline cached query queries

* Updated tailwind to include classes from the ui-lib; Not directly duplicate the base tailwind config that exists in the ui-lib;

* Cleaned up flex gaps;

* Updated hover states feed sidebars with underline instead of strange bg/shadow;

* Updated social presence to Personal Data and only show the matching profiles; Updated pagemeta icons to match;

* Added appearing context menu on mail messages;

* Cleanedup context-menu's;

* Added loading indicator on feed teaser; Added site-data into owner offline cache;

* Build fix;

* Unified query keys with a default query key set; Cleaned up the exagerated cacheTimes;

* Cleaned up excess refetchOnMount: disabled;

* Fix broken queryModified on community load;

* Updated imageplugin to avoid having a cursor within; Fixed post uploader to properly handle a removed default payload;

* Merged all app query caches keys into a single one to allow sharing of cached data;

* Added chat cache query keys into community;

* Add option to remove a stored identity from your storage;

* Avoid 403 on contact drive read for the logged in user contact; Added hasRead & hasWrite access check before running useContact;

* Navigation flow fixes;

* Moved RTE in chat to lazy load

* Fix page metadata connect link;

* Fix occasional blocked contact fetching

* Added more certainty on public-app logout; Refactored connections templates; Hide in/out-coming introductions by default; Always lazy import the RTE;

* Improved volatileInput caret saving/restoring;

* Bit of selection helper cleanup;

* Removed priority as root file property;

* Fix bug in optimistic mutation on remove attribute;

* Fix for empty group chat recipient selection screen;
  • Loading branch information
stef-coenen authored Dec 3, 2024
1 parent bd62209 commit 970c07e
Show file tree
Hide file tree
Showing 241 changed files with 1,497 additions and 2,771 deletions.
4 changes: 4 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 3 additions & 6 deletions packages/apps/chat-app/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ import {

import { Helmet, HelmetProvider } from 'react-helmet-async';

export const REACT_QUERY_CACHE_KEY = 'CHAT_REACT_QUERY_OFFLINE_CACHE';
const REACT_QUERY_INCLUDED_QUERY_KEYS = [
'chat-message',
'chat-messages',
'chat-reaction',
'conversations',
'conversation-metadata',
'chat-reaction',
'connection-details',
'process-inbox',
'process-chat-inbox',
];

import { MinimalLayout, Layout } from '../components/ui/Layout/Layout';
Expand All @@ -36,7 +34,6 @@ const ChatCreateAndOrRedirect = lazy(() =>
}))
);

import '@homebase-id/ui-lib/dist/style.css';
import './App.css';

const AUTH_PATH = CHAT_ROOT_PATH + '/auth';
Expand Down Expand Up @@ -114,7 +111,7 @@ function App() {
<meta name="v" content={import.meta.env.VITE_VERSION} />
</Helmet>
<OdinQueryClient
cacheKey={REACT_QUERY_CACHE_KEY}
cacheKey={'APP_REACT_QUERY_OFFLINE_CACHE'}
cachedQueryKeys={REACT_QUERY_INCLUDED_QUERY_KEYS}
type="indexeddb"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,17 @@ const ConversationBody = ({
const plainLastMessageContent = getPlainTextFromRichText(lastMessageContent?.message);

useEffect(() => {
if (!lastMessage) {
if (conversation) {
const date = conversation?.fileMetadata.updated;
setOrder && date && setOrder(Math.max(new Date().getTime() - date, 2));
}
if (lastMessage) {
const date = lastMessage?.fileMetadata.created;
setOrder && date && setOrder(Math.max(new Date().getTime() - date, 2));
return;
}
const date = lastMessage?.fileMetadata.created;
setOrder && date && setOrder(Math.max(new Date().getTime() - date, 2));
if (conversation) {
const date = conversation?.fileMetadata.updated;
setOrder && date && setOrder(Math.max(new Date().getTime() - date, 2));
return;
}
setOrder && setOrder(2);
}, [lastMessage, conversation]);
const hasNoContextMenu = stringGuidsEqual(conversationId, ConversationWithYourselfId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const GroupContactSearch = ({
const [query, setQuery] = useState<string | undefined>(undefined);

const { data: contacts } = useAllContacts(true);

const contactResults = contacts
? contacts
.map((dsr) => dsr.fileMetadata.appData.content)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { useEffect, useState } from 'react';
import {
ActionButton,
ActionLink,
AuthorImage,
AuthorName,
CHAT_ROOT_PATH,
ConnectionImage,
ConnectionName,
Expand Down Expand Up @@ -95,8 +97,8 @@ export const EditConversationGroup = () => {
className="flex flex-row items-center gap-1 rounded-lg bg-background px-2 py-1 opacity-70"
key={recipient}
>
<ConnectionImage odinId={recipient} size="xs" />
<ConnectionName odinId={recipient} />
<AuthorImage odinId={recipient} size="xs" />
<AuthorName odinId={recipient} />
</div>
))}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,12 @@ export const ContextMenu = ({
},
...optionalOptions,
]}
className="absolute right-1 top-[0.125rem] z-10 rounded-full bg-transparent group-hover:pointer-events-auto group-hover:bg-background/60"
className="absolute right-[0.325rem] top-[0.4rem] z-10 flex-shrink-0 rounded-md bg-background p-1 opacity-0 transition-opacity group-hover:opacity-100"
type={'mute'}
size="square"
size="none"
>
<span className="opacity-0 group-hover:opacity-100">
<ChevronDown className="h-3 w-3" />
<span className="sr-only ml-1">{t('More')}</span>
</span>
<ChevronDown className="h-4 w-4" />
<span className="sr-only ml-1">{t('More')}</span>
</ActionGroup>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ import {
usePortal,
} from '@homebase-id/common-app';
import { UnifiedConversation } from '../../../providers/ConversationProvider';
import { useEffect, useState } from 'react';
import { lazy, Suspense, useEffect, useState } from 'react';
import { useChatMessage } from '../../../hooks/chat/useChatMessage';
import { isTouchDevice } from '@homebase-id/js-lib/helpers';
import { RichTextEditor } from '@homebase-id/rich-text-editor';

const RichTextEditor = lazy(() =>
import('@homebase-id/rich-text-editor').then((rootExport) => ({
default: rootExport.RichTextEditor,
}))
);

export const EditChatMessage = ({
msg,
Expand Down Expand Up @@ -81,14 +86,16 @@ export const EditChatMessage = ({
}
/>
) : (
<RichTextEditor
placeholder="Your message"
defaultValue={message}
className="relative w-full rounded-md border bg-background p-2 dark:border-slate-800"
onChange={(e) => setMessage(e.target.value)}
autoFocus={!isTouchDevice()}
onSubmit={isTouchDevice() ? undefined : () => doSend()}
/>
<Suspense>
<RichTextEditor
placeholder="Your message"
defaultValue={message}
className="relative w-full rounded-md border bg-background p-2 dark:border-slate-800"
onChange={(e) => setMessage(e.target.value)}
autoFocus={!isTouchDevice()}
onSubmit={isTouchDevice() ? undefined : () => doSend()}
/>
</Suspense>
)}
<div className="mt-4 flex flex-row-reverse gap-2">
<ActionButton
Expand Down
8 changes: 5 additions & 3 deletions packages/apps/chat-app/src/hooks/auth/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
AppPermissionType,
AUTO_CONNECTIONS_CIRCLE_ID,
CONFIRMED_CONNECTIONS_CIRCLE_ID,
ContactConfig,
} from '@homebase-id/js-lib/network';
import {
APP_AUTH_TOKEN,
Expand Down Expand Up @@ -71,11 +72,11 @@ export const drives = [
},
{
// Contacts
a: '2612429d1c3f037282b8d42fb2cc0499',
t: '70e92f0f94d05f5c7dcd36466094f3a5',
a: ContactConfig.ContactTargetDrive.alias,
t: ContactConfig.ContactTargetDrive.type,
n: 'Contact Drive',
d: '',
p: DrivePermissionType.Read,
p: DrivePermissionType.Read + DrivePermissionType.Write,
},
];

Expand All @@ -85,6 +86,7 @@ export const permissions = [
AppPermissionType.ReadConnections,
AppPermissionType.SendPushNotifications,
AppPermissionType.SendIntroductions,
AppPermissionType.ReceiveDataFromOtherIdentitiesOnMyBehalf,
];

export const circleDrives = [
Expand Down
5 changes: 2 additions & 3 deletions packages/apps/chat-app/src/hooks/auth/useVerifyToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ export const useVerifyToken = () => {
return (await hasValidYouAuthToken(dotYouClient)) ?? true;
};
return useQuery({
queryKey: ['verifyToken'],
queryKey: ['verify-chat-token'],
queryFn: fetchData,
refetchOnMount: false,
staleTime: MINUTE_IN_MS * 10,
gcTime: MINUTE_IN_MS * 10,
enabled: isAuthenticated,
});
};

export const invalidateVerifyToken = (queryClient: QueryClient) => {
queryClient.invalidateQueries({ queryKey: ['verifyToken'] });
queryClient.invalidateQueries({ queryKey: ['verify-chat-token'] });
};
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const useChatWebsocket = (isEnabled: boolean) => {
],
websocketDrives,
() => {
queryClient.invalidateQueries({ queryKey: ['process-inbox'] });
queryClient.invalidateQueries({ queryKey: ['process-chat-inbox'] });
},
undefined,
'useLiveChatProcessor'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const useInboxProcessor = (connected?: boolean) => {
const chatPostProcessInboxHandler = useChatPostInboxHandler();

const fetchData = async () => {
const lastProcessedTime = queryClient.getQueryState(['process-inbox'])?.dataUpdatedAt;
const lastProcessedTime = queryClient.getQueryState(['process-chat-inbox'])?.dataUpdatedAt;
const lastProcessedWithBuffer = lastProcessedTime && lastProcessedTime - MINUTE_IN_MS * 5;

const processedresult = await processInbox(dotYouClient, ChatDrive, BATCH_SIZE);
Expand All @@ -55,7 +55,7 @@ export const useInboxProcessor = (connected?: boolean) => {

// We refetch this one on mount as each mount the websocket would reconnect, and there might be a backlog of messages
return useQuery({
queryKey: ['process-inbox'],
queryKey: ['process-chat-inbox'],
queryFn: fetchData,
enabled: connected,
staleTime: 500, // 500ms
Expand Down
3 changes: 1 addition & 2 deletions packages/apps/chat-app/src/hooks/chat/useChatMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,7 @@ export const useChatMessage = (props?: {
queryKey: ['chat-message', props?.messageId],
queryFn: () => getMessageByUniqueId(props?.conversationId, props?.messageId as string),
enabled: !!props?.messageId,
refetchOnMount: false,
refetchOnWindowFocus: false,
staleTime: 1000 * 60 * 2, // 2 minutes
}),
send: useMutation({
mutationFn: sendMessage,
Expand Down
1 change: 0 additions & 1 deletion packages/apps/chat-app/src/hooks/chat/useChatMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ export const useChatMessages = (props?: { conversationId: string | undefined })
? lastPage.cursorState
: undefined,
enabled: !!conversationId,
refetchOnMount: false,
staleTime: 1000 * 60 * 60 * 24, // 24 hour
}),
markAsRead: useMutation({
Expand Down
3 changes: 1 addition & 2 deletions packages/apps/chat-app/src/hooks/chat/useConversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,7 @@ export const getConversationQueryOptions: (
) => ({
queryKey: ['conversation', conversationId],
queryFn: () => fetchSingleConversation(dotYouClient, queryClient, conversationId as string),
refetchOnMount: false,
staleTime: 1000 * 60 * 5, // 5 minutes before updates to a conversation on another device are fetched on this one (when you were offline)
staleTime: 1000 * 60 * 60 * 24, // 24 hours
enabled: !!conversationId,
retry: (failureCount, error) => {
if (error.message === 'Conversation not found') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export const ConversationWithYourself: HomebaseFile<UnifiedConversation> = {
payloads: [],
},
serverMetadata: undefined,
priority: 0,
sharedSecretEncryptedKeyHeader: {} as EncryptedKeyHeader,
};

Expand Down
2 changes: 1 addition & 1 deletion packages/apps/chat-app/src/templates/Chat/ChatDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ const ChatHeader = ({
? recipients.filter((recipient) => recipient !== loggedOnIdentity)[0]
: undefined;

const infoChatMatch = useMatch({ path: `${CHAT_ROOT_PATH}/:conversationKey/info` });
const infoChatMatch = useMatch({ path: `${rootPath}/:conversationKey/info` });
const showChatInfo = !!infoChatMatch;

const { mutate: clearChat, error: clearChatError } = useConversation().clearChat;
Expand Down
6 changes: 5 additions & 1 deletion packages/apps/chat-app/tailwind.config.cjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/** @type {import('tailwindcss').Config} */
// eslint-disable-next-line no-undef
module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}', '../../common/common-app/src/**/*.{js,jsx,ts,tsx}'],
content: [
'./src/**/*.{js,jsx,ts,tsx}',
'../../libs/ui-lib/src/**/*.{js,jsx,ts,tsx}',
'../../common/common-app/src/**/*.{js,jsx,ts,tsx}',
],
theme: {
extend: {
colors: {
Expand Down
21 changes: 16 additions & 5 deletions packages/apps/community-app/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {

import { Helmet, HelmetProvider } from 'react-helmet-async';
import { Layout, MinimalLayout } from '../components/ui/Layout/Layout';
import '@homebase-id/ui-lib/dist/style.css';
import './App.css';
import {
COMMUNITY_ROOT_PATH,
Expand All @@ -24,16 +23,22 @@ import {
} from '@homebase-id/common-app';
import { useValidateAuthorization } from '../hooks/auth/useAuth';

export const REACT_QUERY_CACHE_KEY = 'COMMUNITY_REACT_QUERY_OFFLINE_CACHE';
const REACT_QUERY_INCLUDED_QUERY_KEYS = [
'connection-details',
'process-inbox',
// Community specific
'process-community-inbox',
'communities',
'community',
'community-metadata',
'community-channels',
'community-messages',
'channels-with-recent-message',

// Chat specific:
'chat-message',
'chat-messages',
'chat-reaction',
'conversations',
'conversation-metadata',
];
const AUTH_PATH = COMMUNITY_ROOT_PATH + '/auth';
const AUTH_FINALIZE_PATH = COMMUNITY_ROOT_PATH + '/auth/finalize';
Expand Down Expand Up @@ -155,6 +160,7 @@ function App() {
/>

{/* Items for 'direct'*/}
<Route path={'direct'} element={<NavigateToCommunityRoot />} />
<Route path={'direct/:dmKey'} element={<CommunityDirectDetail />} />
<Route path={'direct/:dmKey/:chatMessageKey'} element={<CommunityDirectDetail />} />
<Route
Expand Down Expand Up @@ -185,7 +191,7 @@ function App() {
<meta name="v" content={import.meta.env.VITE_VERSION} />
</Helmet>
<OdinQueryClient
cacheKey={REACT_QUERY_CACHE_KEY}
cacheKey={'APP_REACT_QUERY_OFFLINE_CACHE'}
cachedQueryKeys={REACT_QUERY_INCLUDED_QUERY_KEYS}
type="indexeddb"
>
Expand All @@ -204,6 +210,11 @@ const CommunityRootRoute = () => {
) : null;
};

const NavigateToCommunityRoot = () => {
const { odinKey, communityKey } = useParams();
return <Navigate to={`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}`} />;
};

const RootRoute = ({ children }: { children: ReactNode }) => {
useValidateAuthorization();
const location = useLocation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@ import {
useLinkPreviewBuilder,
VolatileInputRef,
} from '@homebase-id/common-app';
import { useState, useEffect, FC, useRef } from 'react';
import { useState, useEffect, FC, useRef, lazy } from 'react';

import { getNewId, isTouchDevice } from '@homebase-id/js-lib/helpers';
import { ChatComposerProps } from '@homebase-id/chat-app/src/components/Chat/Composer/ChatComposer';
import { HomebaseFile, NewMediaFile, RichText } from '@homebase-id/js-lib/core';
import { useChatMessage } from '@homebase-id/chat-app/src/hooks/chat/useChatMessage';
import { Plus, PaperPlane, Times } from '@homebase-id/common-app/icons';
import { LinkPreview } from '@homebase-id/js-lib/media';
import { RichTextEditor } from '@homebase-id/rich-text-editor';
const RichTextEditor = lazy(() =>
import('@homebase-id/rich-text-editor').then((rootExport) => ({
default: rootExport.RichTextEditor,
}))
);
import { EmbeddedMessage } from '@homebase-id/chat-app/src/components/Chat/Detail/EmbeddedMessage';
import { ChatMessage } from '@homebase-id/chat-app/src/providers/ChatProvider';

Expand Down
Loading

0 comments on commit 970c07e

Please sign in to comment.