diff --git a/packages/chat-app/src/components/Chat/Detail/Media/ChatMediaGallery.tsx b/packages/chat-app/src/components/Chat/Detail/Media/ChatMediaGallery.tsx index 140f4d1c1..fb281432b 100644 --- a/packages/chat-app/src/components/Chat/Detail/Media/ChatMediaGallery.tsx +++ b/packages/chat-app/src/components/Chat/Detail/Media/ChatMediaGallery.tsx @@ -77,8 +77,6 @@ export const ChatMediaGallery = ({ msg }: { msg: HomebaseFile<ChatMessage> }) => return () => window.removeEventListener('keydown', handleKeyDown); }, [msg, mediaKey]); - // TODO: Added previewThumbnail of the grid - const payload = msg.fileMetadata.payloads.find((p) => p.key === mediaKey); const contentType = payload?.contentType; const dialog = ( diff --git a/packages/chat-app/src/hooks/chat/useChatMessages.ts b/packages/chat-app/src/hooks/chat/useChatMessages.ts index 7aa6bb535..3b35ba8a1 100644 --- a/packages/chat-app/src/hooks/chat/useChatMessages.ts +++ b/packages/chat-app/src/hooks/chat/useChatMessages.ts @@ -47,10 +47,7 @@ export const useChatMessages = (props?: { conversationId: string | undefined }) !recipientStatus.status || recipientStatus.status?.toLowerCase() !== SendReadReceiptResponseRecipientStatus.Enqueued ); - if (someFailed) { - // TODO: Should we throw an error? - console.error('Error marking chat as read', { response }); - } + if (someFailed) console.error('Error marking chat as read', { response }); }); return response; diff --git a/packages/chat-app/src/providers/ChatProvider.ts b/packages/chat-app/src/providers/ChatProvider.ts index 052d8fd27..0e67acc4a 100644 --- a/packages/chat-app/src/providers/ChatProvider.ts +++ b/packages/chat-app/src/providers/ChatProvider.ts @@ -464,7 +464,7 @@ export const softDeleteChatMessage = async ( for (let i = 0; i < message.fileMetadata.payloads.length; i++) { const payload = message.fileMetadata.payloads[i]; - // TODO: Should the payload be deleted for everyone? With "TransitOptions" + // TODO: Should the payload be deleted for everyone? With "TransitOptions"; Needs server side support for it; const deleteResult = await deletePayload( dotYouClient, ChatDrive, diff --git a/packages/common-app/src/hooks/transitProcessor/useWebsocketSubscriber.ts b/packages/common-app/src/hooks/transitProcessor/useWebsocketSubscriber.ts index 39093420a..d87bed148 100644 --- a/packages/common-app/src/hooks/transitProcessor/useWebsocketSubscriber.ts +++ b/packages/common-app/src/hooks/transitProcessor/useWebsocketSubscriber.ts @@ -70,7 +70,9 @@ export const useWebsocketSubscriber = ( () => { setIsConected(true); onReconnect && onReconnect(); - } + }, + undefined, + refId ); setIsConected(true); })(); diff --git a/packages/community-app/src/components/Community/Message/detail/CommunityMediaGallery.tsx b/packages/community-app/src/components/Community/Message/detail/CommunityMediaGallery.tsx index 4b6366c3f..9a31f817e 100644 --- a/packages/community-app/src/components/Community/Message/detail/CommunityMediaGallery.tsx +++ b/packages/community-app/src/components/Community/Message/detail/CommunityMediaGallery.tsx @@ -85,8 +85,6 @@ export const CommunityMediaGallery = ({ return () => window.removeEventListener('keydown', handleKeyDown); }, [msg, mediaKey]); - // TODO: Added previewThumbnail of the grid - const payload = msg.fileMetadata.payloads.find((p) => p.key === mediaKey); const contentType = payload?.contentType; const dialog = ( diff --git a/packages/community-app/src/hooks/community/useLiveCommunityProcessor.ts b/packages/community-app/src/hooks/community/useLiveCommunityProcessor.ts index 5b84b3c4c..e1c23f4a5 100644 --- a/packages/community-app/src/hooks/community/useLiveCommunityProcessor.ts +++ b/packages/community-app/src/hooks/community/useLiveCommunityProcessor.ts @@ -288,7 +288,9 @@ const useCommunityWebsocket = (communityId: string | undefined, isEnabled: boole [targetDrive], () => { queryClient.invalidateQueries({ queryKey: ['process-inbox'] }); - } + }, + undefined, + 'useLiveCommunityProcessor' ); }; diff --git a/packages/feed-app/src/hooks/useLiveFeedProcessor.ts b/packages/feed-app/src/hooks/useLiveFeedProcessor.ts index a4646a9aa..342a39abd 100644 --- a/packages/feed-app/src/hooks/useLiveFeedProcessor.ts +++ b/packages/feed-app/src/hooks/useLiveFeedProcessor.ts @@ -69,6 +69,9 @@ const useFeedWebSocket = (isEnabled: boolean) => { useWebsocketSubscriber( isEnabled ? handler : undefined, ['fileAdded', 'fileModified'], - websocketDrives + websocketDrives, + undefined, + undefined, + 'useLiveFeedProcessor' ); }; diff --git a/packages/js-lib/src/core/WebsocketData/WebsocketProvider.ts b/packages/js-lib/src/core/WebsocketData/WebsocketProvider.ts index 7c3b9e7e5..20557ac8f 100644 --- a/packages/js-lib/src/core/WebsocketData/WebsocketProvider.ts +++ b/packages/js-lib/src/core/WebsocketData/WebsocketProvider.ts @@ -276,7 +276,8 @@ export const Subscribe = async ( handler: (data: TypedConnectionNotification) => void, onDisconnect?: () => void, onReconnect?: () => void, - args?: unknown // Extra parameters to pass to WebSocket constructor; Only applicable for React Native...; TODO: Remove this + args?: unknown, // Extra parameters to pass to WebSocket constructor; Only applicable for React Native...; TODO: Remove this, + refId?: string ): Promise<void> => { const apiType = dotYouClient.getType(); const sharedSecret = dotYouClient.getSharedSecret(); @@ -287,7 +288,8 @@ export const Subscribe = async ( activeSs = sharedSecret; subscribers.push({ handler, onDisconnect, onReconnect }); - if (isDebug) console.debug(`[NotificationProvider] New subscriber (${subscribers.length})`); + if (isDebug) + console.debug(`[NotificationProvider] New subscriber (${subscribers.length})`, refId); // Already connected, no need to initiate a new connection if (webSocketClient) return Promise.resolve(); diff --git a/packages/js-lib/src/helpers/BrowserUtil.ts b/packages/js-lib/src/helpers/BrowserUtil.ts index 22ca35c0b..b1ffa6e2e 100644 --- a/packages/js-lib/src/helpers/BrowserUtil.ts +++ b/packages/js-lib/src/helpers/BrowserUtil.ts @@ -12,4 +12,8 @@ export const isLocalStorageAvailable = () => { export const isTouchDevice = () => 'ontouchstart' in window || navigator.maxTouchPoints > 0; export const hasDebugFlag = () => - isLocalStorageAvailable() ? localStorage.getItem('debug') === '1' : false; + isLocalStorageAvailable() + ? localStorage.getItem('debug') === '1' + : typeof navigator !== 'undefined' && + navigator.product === 'ReactNative' && + (global as any).debug; diff --git a/packages/js-lib/src/media/Link/LinkPreviewProvider.ts b/packages/js-lib/src/media/Link/LinkPreviewProvider.ts index 6b332183a..4df21f105 100644 --- a/packages/js-lib/src/media/Link/LinkPreviewProvider.ts +++ b/packages/js-lib/src/media/Link/LinkPreviewProvider.ts @@ -49,8 +49,8 @@ export const getLinkPreview = async ( title: response.data.title || '', description: response.data.description || '', imageUrl: response.data.imageUrl || undefined, - imageWidth: response.data.imageWidth || undefined, // TODO: Should we find a way to always get one from the dataUri? - imageHeight: response.data.imageHeight || undefined, // TODO: Should we find a way to always get one from the dataUri? + imageWidth: response.data.imageWidth || undefined, + imageHeight: response.data.imageHeight || undefined, url: response.data.url, }; }) diff --git a/packages/js-lib/src/public/posts/PostProvider.ts b/packages/js-lib/src/public/posts/PostProvider.ts index 9decdd03e..055cccf0f 100644 --- a/packages/js-lib/src/public/posts/PostProvider.ts +++ b/packages/js-lib/src/public/posts/PostProvider.ts @@ -209,8 +209,7 @@ export const removePost = async ( const targetDrive = GetTargetDriveFromChannelId(channelId); if (postFile.fileMetadata.globalTransitId) { - // Fetch the first 1000 comments and delete them with the post; - // TODO: this should support a larger numbers of comments; Or a delete of a tree of groupIds + // Fetch the first 1000 comments and delete their level 2 replies by groupId; const comments = ( await queryBatch( dotYouClient, diff --git a/packages/js-lib/src/public/posts/PostUploadProvider.ts b/packages/js-lib/src/public/posts/PostUploadProvider.ts index 0928bb231..59b42472e 100644 --- a/packages/js-lib/src/public/posts/PostUploadProvider.ts +++ b/packages/js-lib/src/public/posts/PostUploadProvider.ts @@ -234,7 +234,7 @@ const uploadPost = async <T extends PostContent>( recipients: [], schedule: ScheduleOptions.SendLater, priority: PriorityOptions.Medium, - sendContents: SendContents.All, // TODO: Should this be header only? + sendContents: SendContents.All, }, }; @@ -346,7 +346,7 @@ const uploadPostHeader = async <T extends PostContent>( recipients: [], schedule: ScheduleOptions.SendLater, priority: PriorityOptions.Medium, - sendContents: SendContents.All, // TODO: Should this be header only? + sendContents: SendContents.All, }, }; diff --git a/packages/mail-app/src/hooks/mail/useLiveMailProcessor.ts b/packages/mail-app/src/hooks/mail/useLiveMailProcessor.ts index 0f65e54d9..ab2d7066d 100644 --- a/packages/mail-app/src/hooks/mail/useLiveMailProcessor.ts +++ b/packages/mail-app/src/hooks/mail/useLiveMailProcessor.ts @@ -78,15 +78,6 @@ const useMailWebsocket = (isEnabled: boolean) => { ); if (!updatedChatMessage) return; - const sender = - notification.header.fileMetadata.senderOdinId || - updatedChatMessage.fileMetadata.appData.content.sender; - - if (!sender || sender === identity) { - // Ignore messages sent by the current user - return; - } - const existingConversations = queryClient.getQueryData< InfiniteData<MailConversationsReturn> >(['mail-conversations']); @@ -127,6 +118,8 @@ const useMailWebsocket = (isEnabled: boolean) => { websocketDrives, () => { queryClient.invalidateQueries({ queryKey: ['process-inbox'] }); - } + }, + undefined, + 'useLiveMailProcessor' ); }; diff --git a/packages/mail-app/src/hooks/mail/useMailConversation.ts b/packages/mail-app/src/hooks/mail/useMailConversation.ts index 0d9264024..f4ad9ff63 100644 --- a/packages/mail-app/src/hooks/mail/useMailConversation.ts +++ b/packages/mail-app/src/hooks/mail/useMailConversation.ts @@ -211,10 +211,6 @@ export const useMailConversation = (props?: { messageFileId: string }) => { queryClient.setQueryData(['mail-conversations'], context?.existingConversations); console.error('Error sending mail message', _error); }, - onSettled: async () => { - // TODO: Should we really fully refetch the mail conversations and mail thread? Might be a lot of data... - queryClient.invalidateQueries({ queryKey: ['mail-conversations'] }); - }, }), markAsRead: useMutation({ mutationFn: markAsRead, @@ -528,10 +524,6 @@ export const useMailDraft = (props?: { draftFileId: string }) => { console.error('Error removing draft mail message', _error); }, - onSettled: async () => { - queryClient.invalidateQueries({ queryKey: ['mail-conversations'] }); - // Should we fully refetch the mail conversations and mail thread? Might be a lot of data... - }, }), }; }; diff --git a/packages/mail-app/src/hooks/mail/useMailThread.ts b/packages/mail-app/src/hooks/mail/useMailThread.ts index d95d9de2d..0c76a9b0e 100644 --- a/packages/mail-app/src/hooks/mail/useMailThread.ts +++ b/packages/mail-app/src/hooks/mail/useMailThread.ts @@ -113,11 +113,6 @@ export const useMailThread = (props?: { threadId: string | undefined }) => { console.error('Error removing messages', error); }, - onSettled: () => { - // TODO: This can be optimized to use the uploadResults to update the versionTag; - // Just not sure if it should live here, or be part fo the websocket connection? - queryClient.invalidateQueries({ queryKey: ['mail-conversations'] }); - }, }), archive: useMutation({ mutationFn: archiveMailThread, diff --git a/packages/owner-app/src/components/ui/Sections/CollapsableSection.tsx b/packages/owner-app/src/components/ui/Sections/CollapsableSection.tsx deleted file mode 100644 index 6fb96057d..000000000 --- a/packages/owner-app/src/components/ui/Sections/CollapsableSection.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { Arrow } from '@homebase-id/common-app/icons'; -import { ReactNode, useEffect, useRef, useState } from 'react'; - -const CollapsableSection = ({ - isOpenByDefault = true, - title, - className, - children, - isBorderLess = false, -}: { - isOpenByDefault?: boolean; - title: ReactNode; - className?: string; - children: ReactNode; - isBorderLess?: boolean; -}) => { - const [isOpen, setIsOpen] = useState(isOpenByDefault); - const sectionContainerRef = useRef<HTMLDivElement>(null); - const height = useRef(0); - - useEffect(() => { - if (isOpenByDefault && sectionContainerRef.current) { - height.current = sectionContainerRef.current.clientHeight; - } - // Todo apply FLIP approach (when not open by default) to calculate the to-be height when we can't use the height of the open state - }, [isOpen]); - - return ( - <section - className={`my-5 flex flex-col rounded-md shadow-sm ${ - !isBorderLess - ? 'rounded-lg border border-gray-200 border-opacity-80 dark:border-gray-700' - : '' - } - bg-white px-5 dark:bg-slate-900 dark:text-slate-300 ${className ?? ''}`} - > - <div - className={`relative cursor-pointer border-b-[1px] border-slate-200 py-5 transition-all duration-300 ${ - isOpen ? 'border-opacity-100' : 'border-opacity-0' - }`} - onClick={() => setIsOpen(!isOpen)} - > - <h3 className="pr-6 text-2xl dark:text-white">{title}</h3> - <button className="absolute bottom-0 right-0 top-0"> - <Arrow - className={`h-5 w-5 transition-transform duration-300 ${ - isOpen ? 'rotate-90' : '-rotate-90' - }`} - /> - </button> - </div> - <div - className={`overflow-hidden transition-all duration-300 `} - style={{ maxHeight: `${isOpen ? (height.current ? height.current : 2000) : 0}px` }} - ref={sectionContainerRef} - > - <div className="py-5 ">{children}</div> - </div> - </section> - ); -}; - -export default CollapsableSection; diff --git a/packages/owner-app/src/hooks/configure/useInit.ts b/packages/owner-app/src/hooks/configure/useInit.ts index 1c21af2fe..47ecf9343 100644 --- a/packages/owner-app/src/hooks/configure/useInit.ts +++ b/packages/owner-app/src/hooks/configure/useInit.ts @@ -60,7 +60,7 @@ export const useInit = () => { } // Do a first publish of the static files - // This is normally a side effect from the useAttribute hook.. TODO: Move to providers instead of the hook + // This is normally a side effect from the useAttribute hook.. but we need to do it here after the first setup await publishStaticFiles(undefined); const defaultServerSettings = getSettings(dotYouClient); diff --git a/packages/owner-app/src/hooks/contacts/useContact.ts b/packages/owner-app/src/hooks/contacts/useContact.ts index 325810738..bbb3ec8a8 100644 --- a/packages/owner-app/src/hooks/contacts/useContact.ts +++ b/packages/owner-app/src/hooks/contacts/useContact.ts @@ -58,7 +58,6 @@ export const useContact = ({ // Direct fetch with odinId: // Use the data from the contact book, if it exists and if it's a contact level source or we are not allowed to save anyway - // TODO: Not sure if this is the best way yet... But it works for now const contactBookContact = await getContactByOdinId(dotYouClient, odinId); if ( !hasCache && // If we have a contact on drive, and we don't have cache, we need a fast return; Otherwise we trigger a refresh diff --git a/packages/owner-app/src/hooks/profiles/useAttributes.ts b/packages/owner-app/src/hooks/profiles/useAttributes.ts index a7b90f61d..bc6b5e947 100644 --- a/packages/owner-app/src/hooks/profiles/useAttributes.ts +++ b/packages/owner-app/src/hooks/profiles/useAttributes.ts @@ -27,7 +27,7 @@ export const useAttributes = ({ profileId, sectionId, undefined, - 100 // TODO: Should we page this properly, or how many profile attributes do we expect as normal? + 200 // TODO: Should we page this properly, or how many profile attributes do we expect being "normal"? ); return foundAttributes.map((attr) => { diff --git a/packages/owner-app/src/templates/DemoData/DemoData.tsx b/packages/owner-app/src/templates/DemoData/DemoData.tsx index 831fd5103..22a06744a 100644 --- a/packages/owner-app/src/templates/DemoData/DemoData.tsx +++ b/packages/owner-app/src/templates/DemoData/DemoData.tsx @@ -408,7 +408,7 @@ const DemoDataProfile = ({ client, realmData }: { client: DotYouClient; realmDat <h1>Profile:</h1> <button onClick={addName} - className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ + className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ isNameSet ? 'pointer-events-none bg-gray-300' : 'bg-green-500' }`} disabled={isNameSet} @@ -417,7 +417,7 @@ const DemoDataProfile = ({ client, realmData }: { client: DotYouClient; realmDat </button> <button onClick={addPhoto} - className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ + className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ attrHasData(photoAttr) && isPhotoFetched ? 'pointer-events-none bg-gray-300' : 'bg-green-500' @@ -428,7 +428,7 @@ const DemoDataProfile = ({ client, realmData }: { client: DotYouClient; realmDat </button> <button onClick={addSocials} - className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ + className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ attrHasData(socialAttr) && isSocialFetched ? 'pointer-events-none bg-gray-300' : 'bg-green-500' @@ -439,7 +439,7 @@ const DemoDataProfile = ({ client, realmData }: { client: DotYouClient; realmDat </button> <button onClick={addBiography} - className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ + className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ bioAttr && isBioFetched ? 'pointer-events-none bg-gray-300' : 'bg-green-500' }`} disabled={(bioAttr && isBioFetched) || false} @@ -513,10 +513,6 @@ const DemoDataHomeAndTheme = ({ realmData }: { client: DotYouClient; realmData: { type: 'image/webp' } ); - // TODO: Save tag and leadText into status and shortBio attributes - // StatusAttr.data[HomePageThemeFields.TagLineId] = realmData.home.tagLine; - // ShortBioAttr.data[HomePageThemeFields.LeadTextId] = realmData.home.lead; - saveRoot({ fileMetadata: { appData: { @@ -536,7 +532,7 @@ const DemoDataHomeAndTheme = ({ realmData }: { client: DotYouClient; realmData: <h1>Theme:</h1> <button onClick={addTheme} - className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ + className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ hasThemeData ? 'pointer-events-none bg-gray-300' : 'bg-green-500' }`} disabled={!!hasThemeData} @@ -683,7 +679,7 @@ const DemoDataBlog = ({ <h1>Blog:</h1> <button onClick={addChannels} - className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ + className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ channelAttr && isChannelFetched ? 'pointer-events-none bg-gray-300' : 'bg-green-500' }`} disabled={(channelAttr && isChannelFetched) || false} @@ -746,7 +742,7 @@ const CirclesAndConnections = ({ realmData }: { realmData: RealmData }) => { <h1>Circles and Connections:</h1> <button onClick={createCircles} - className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ + className={`my-2 block w-1/3 rounded border-0 px-4 py-2 text-white hover:bg-green-600 focus:outline-none ${ hasDemoCircles ? 'pointer-events-none bg-gray-300' : 'bg-green-500' }`} disabled={hasDemoCircles || false} diff --git a/packages/owner-app/src/templates/FirstRun/FirstRun.tsx b/packages/owner-app/src/templates/FirstRun/FirstRun.tsx index 03d8c08c0..fa6b8c6f0 100644 --- a/packages/owner-app/src/templates/FirstRun/FirstRun.tsx +++ b/packages/owner-app/src/templates/FirstRun/FirstRun.tsx @@ -8,7 +8,14 @@ import UrlNotifier from '../../components/ui/Layout/UrlNotifier/UrlNotifier'; import { useSearchParams } from 'react-router-dom'; import { FIRST_RUN_TOKEN_STORAGE_KEY } from '../../hooks/configure/useInit'; -import { ActionButton, Alert, DomainHighlighter, Label, t } from '@homebase-id/common-app'; +import { + ActionButton, + Alert, + DomainHighlighter, + ErrorNotification, + Label, + t, +} from '@homebase-id/common-app'; import { Arrow } from '@homebase-id/common-app/icons'; import { PasswordInput } from '../../components/Password/PasswordInput'; import { PasswordStrength } from '../../components/Password/PasswordStrength'; @@ -18,6 +25,7 @@ const FirstRun = () => { const [retypePassword, setRetypePassword] = useState(''); const [state, setState] = useState<'loading' | 'error' | 'success' | undefined>(); + const [error, setError] = useState<unknown | undefined>(); const { authenticate, finalizeRegistration } = useAuth(); const [searchParams] = useSearchParams(); @@ -35,9 +43,10 @@ const FirstRun = () => { setState('success'); } catch (ex) { - // Todo show message what failed - console.error(ex); + setError(ex); setState('error'); + + console.error(ex); } return false; }; @@ -48,8 +57,10 @@ const FirstRun = () => { <title>Setup | Homebase</title> </Helmet> <MinimalLayout noShadedBg={true} noPadding={true}> + <ErrorNotification error={error} /> <UrlNotifier /> - <section className="body-font flex h-full pt-24 "> + + <section className="body-font flex h-full pt-24"> <div className="container m-auto h-full max-w-[35rem] p-5"> <form onSubmit={doNext}> <h1 className="mb-5 text-4xl dark:text-white"> @@ -65,7 +76,7 @@ const FirstRun = () => { ) : ( <> <div className="mb-2"> - <Label htmlFor="password" className="text-sm leading-7 dark:text-gray-400"> + <Label htmlFor="password" className="text-sm leading-7 dark:text-gray-400"> {t('Password')} </Label> <PasswordInput @@ -83,7 +94,7 @@ const FirstRun = () => { <div className="mb-4"> <Label htmlFor="retypepassword" - className="text-sm leading-7 dark:text-gray-400" + className="text-sm leading-7 dark:text-gray-400" > {t('Retype Password')} </Label> diff --git a/packages/owner-app/src/templates/Login/Login.tsx b/packages/owner-app/src/templates/Login/Login.tsx index a97d30915..4da928927 100644 --- a/packages/owner-app/src/templates/Login/Login.tsx +++ b/packages/owner-app/src/templates/Login/Login.tsx @@ -5,13 +5,20 @@ import { MinimalLayout } from '../../components/ui/Layout/Layout'; import UrlNotifier from '../../components/ui/Layout/UrlNotifier/UrlNotifier'; import { Link } from 'react-router-dom'; import { PasswordInput } from '../../components/Password/PasswordInput'; -import { t, DomainHighlighter, Label, ActionButton } from '@homebase-id/common-app'; +import { + t, + DomainHighlighter, + Label, + ActionButton, + ErrorNotification, +} from '@homebase-id/common-app'; import { Loader, Arrow } from '@homebase-id/common-app/icons'; const Login = () => { const [password, setPassword] = useState(import.meta.env.DEV ? 'a' : ''); const [passwordState, setPasswordState] = useState<'unknown' | 'pending' | 'ready'>('unknown'); const [state, setState] = useState<'loading' | 'error' | 'success' | undefined>(); + const [error, setError] = useState<unknown | undefined>(); const { authenticate, setFirstPassword, isPasswordSet, isAuthenticated } = useAuth(); const doLogin: FormEventHandler = async (e) => { @@ -21,9 +28,9 @@ const Login = () => { await authenticate(password); setState('success'); } catch (ex) { - // Todo show message what failed - console.error(ex); setState('error'); + setError(ex); + console.error(ex); } return false; }; @@ -47,6 +54,7 @@ const Login = () => { if (passwordState === 'unknown' || passwordState === 'pending' || isAuthenticated) { return ( <MinimalLayout noShadedBg={true} noPadding={true}> + <ErrorNotification error={error} /> <div className="h-screen"> <div className="mx-auto flex min-h-full w-full max-w-3xl flex-col p-5"> <div className="my-auto flex flex-col"> @@ -77,7 +85,7 @@ const Login = () => { </small> </h1> <div className="mb-4"> - <Label htmlFor="password" className="text-sm leading-7 dark:text-gray-400"> + <Label htmlFor="password" className="text-sm leading-7 dark:text-gray-400"> Password </Label> <PasswordInput diff --git a/packages/owner-app/src/templates/YouAuthConsent/YouAuthConsent.tsx b/packages/owner-app/src/templates/YouAuthConsent/YouAuthConsent.tsx index d36253fe5..494f803f1 100644 --- a/packages/owner-app/src/templates/YouAuthConsent/YouAuthConsent.tsx +++ b/packages/owner-app/src/templates/YouAuthConsent/YouAuthConsent.tsx @@ -118,7 +118,6 @@ const YouAuthConsent = () => { ) : null} <div className="mt-8 flex flex-col gap-2 sm:flex-row-reverse"> - {/* TODO: Check if this would be better with a normal XHR request... Having a form is pretty uncommon, and doesn't add anything in terms of security */} <form action="/api/owner/v1/youauth/authorize" method="post" className="contents"> <input type="hidden" name="return_url" value={returnUrl} /> {consentRequirements ? ( diff --git a/packages/ui-lib/src/components/OdinVideo/OdinVideo.tsx b/packages/ui-lib/src/components/OdinVideo/OdinVideo.tsx index ebc18c365..8f2dbcca4 100644 --- a/packages/ui-lib/src/components/OdinVideo/OdinVideo.tsx +++ b/packages/ui-lib/src/components/OdinVideo/OdinVideo.tsx @@ -73,7 +73,6 @@ export const OdinVideo = (videoProps: OdinVideoProps) => { ) return 'direct'; - // TODO: Need to know for sure if we are encrypted or not, for now we assume based on the hint if (videoMetaData?.isSegmented && videoProps.probablyEncrypted) return 'encrypted-mse'; if (videoMetaData?.isSegmented) return 'mse';