Skip to content

Commit

Permalink
Test prototype (#29)
Browse files Browse the repository at this point in the history
* Added push notification provider; Extended transitoptions with the usepushnotification flag;

* Small ui updates;

* Updates;

* Improved handling of incoming push notifications;

* Better handling and sending of tagId to existing notifications page;

* Avoid sending empty messages;

* Added relative date formatter to timeago helper'

* Updates;

* Updated clearing of push registration; Improvements and polishing of the notification list view;

* Extended PushNotificationOptions type;

* Some more polishing;

* Added handling of new errorCode format;

* Temp disabled the old notifications;
  • Loading branch information
stef-coenen authored Dec 7, 2023
1 parent dc5c8e7 commit 9e87730
Show file tree
Hide file tree
Showing 27 changed files with 544 additions and 239 deletions.
2 changes: 1 addition & 1 deletion packages/chat-app/src/components/Chat/ChatHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export const ChatHistory = ({
key={conversation?.fileId}
>
<div
className="relative w-full flex-shrink-0 flex-grow-0" //overflow-hidden => Might need this one again, to avoid a growing height
className="relative w-full flex-shrink-0 flex-grow-0 overflow-hidden" //TODO remove overflow-hidden when less height than window => Might need this one again, to avoid a growing height
style={{
height: virtualizer.getTotalSize(),
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ export const ChatComposer = ({
placeholder="Your message"
defaultValue={message}
className="rounded-md border bg-background p-2 dark:border-slate-800"
onChange={setMessage}
onChange={(val) => setMessage(val.trim())}
autoFocus={true}
onSubmit={(val) => {
setMessage(val);
setMessage(val.trim());
doSend();
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ const ConversationBody = ({
{typeof title === 'string' ? ellipsisAtMaxChar(title, 25) : title}
</p>

{lastMessage ? <ChatSentTimeIndicator msg={lastMessage} isShort={true} /> : null}
{lastMessage ? <ChatSentTimeIndicator msg={lastMessage} keepDetail={true} /> : null}
</div>
<div className="flex flex-row items-center gap-1">
{lastMessage ? <ChatDeliveryIndicator msg={lastMessage} /> : null}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { t } from '@youfoundation/common-app';
import { format } from '@youfoundation/common-app/src/helpers/timeago';
import { DriveSearchResult } from '@youfoundation/js-lib/core';
import { ChatMessage } from '../../../providers/ChatProvider';
import { formatToTimeAgoWithRelativeDetail } from '@youfoundation/common-app/src/helpers/timeago/format';

export const ChatSentTimeIndicator = ({
msg,
className,
isShort,
keepDetail,
}: {
msg: DriveSearchResult<ChatMessage>;
className?: string;
isShort?: boolean;
keepDetail?: boolean;
}) => {
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<p className={`select-none text-sm text-foreground/70 ${className || ''}`}>{children}</p>
Expand All @@ -19,42 +19,5 @@ export const ChatSentTimeIndicator = ({
const date = new Date(msg.fileMetadata.created);
if (!date) return <Wrapper>{t('Unknown')}</Wrapper>;

const oneHourAgo = new Date();
oneHourAgo.setHours(oneHourAgo.getHours() - 1);
if (date > oneHourAgo)
return <Wrapper>{format(date).replaceAll('ago', '').replaceAll('just', '')}</Wrapper>;

// if date is not today
const today = new Date();
today.setHours(0, 0, 0, 0);
if (date >= today) {
const timeFormat: Intl.DateTimeFormatOptions = {
hour: 'numeric',
minute: 'numeric',
};
return <Wrapper>{date.toLocaleTimeString(undefined, timeFormat)}</Wrapper>;
}

// if date is this week
const thisWeek = new Date();
thisWeek.setDate(thisWeek.getDate() - thisWeek.getDay());
if (date >= thisWeek) {
const weekdayFormat: Intl.DateTimeFormatOptions = {
weekday: 'short',
};
return <Wrapper>{date.toLocaleDateString(undefined, weekdayFormat)}</Wrapper>;
}

const now = new Date();
const yearsAgo = Math.abs(new Date(now.getTime() - date.getTime()).getUTCFullYear() - 1970);
// const monthsAgo = Math.abs(now.getMonth() - date.getMonth());
const dateTimeFormat: Intl.DateTimeFormatOptions = {
month: isShort ? 'numeric' : 'short',
day: 'numeric',
// weekday: 'short',
year: yearsAgo !== 0 ? 'numeric' : undefined,
hour: isShort ? undefined : 'numeric',
minute: isShort ? undefined : 'numeric',
};
return <Wrapper>{date.toLocaleDateString(undefined, dateTimeFormat)}</Wrapper>;
return <Wrapper>{formatToTimeAgoWithRelativeDetail(date, keepDetail)}</Wrapper>;
};
1 change: 1 addition & 0 deletions packages/chat-app/src/hooks/auth/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export const useYouAuthAuthorization = () => {
AppPermissionType.SendDataToOtherIdentitiesOnMyBehalf,
AppPermissionType.ReceiveDataFromOtherIdentitiesOnMyBehalf,
AppPermissionType.ReadConnections,
AppPermissionType.SendPushNotifications,
],
undefined,
drives,
Expand Down
4 changes: 2 additions & 2 deletions packages/chat-app/src/hooks/chat/useChatCommandProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const joinConversation = async (
});
queryClient.invalidateQueries({ queryKey: ['conversations'] });
} catch (ex: any) {
if (ex?.response?.data?.errorCode === 4105) return command.id;
if (ex?.response?.data?.errorCode === 'existingFileWithUniqueId') return command.id;

console.error(ex);
return null;
Expand Down Expand Up @@ -155,7 +155,7 @@ const joinGroupConversation = async (
});
queryClient.invalidateQueries({ queryKey: ['conversations'] });
} catch (ex: any) {
if (ex?.response?.data?.errorCode === 4105) return command.id;
if (ex?.response?.data?.errorCode === 'existingFileWithUniqueId') return command.id;

console.error(ex);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const useChatTransitProcessor = (isEnabled = true) => {
command: 'processInbox',
data: JSON.stringify({
targetDrive: notification.externalFileIdentifier.targetDrive,
batchSize: 1,
batchSize: 100,
}),
});
}
Expand Down
10 changes: 9 additions & 1 deletion packages/chat-app/src/providers/ChatProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ import {
GroupConversation,
SingleConversation,
} from './ConversationProvider';
import { jsonStringify64 } from '@youfoundation/js-lib/helpers';
import { getNewId, jsonStringify64 } from '@youfoundation/js-lib/helpers';
import { makeGrid } from '@youfoundation/js-lib/helpers';
import { NewMediaFile } from '@youfoundation/js-lib/public';
import { appId } from '../hooks/auth/useAuth';

export const ChatMessageFileType = 7878;
export const ChatDeletedArchivalStaus = 2;
Expand Down Expand Up @@ -189,6 +190,13 @@ export const uploadChatMessage = async (
schedule: ScheduleOptions.SendNowAwaitResponse,
sendContents: SendContents.All,
useGlobalTransitId: true,
useAppNotification: true,
appNotificationOptions: {
appId: appId,
typeId: message.fileMetadata.appData.groupId as string,
tagId: getNewId(),
silent: false,
},
}
: undefined,
};
Expand Down
1 change: 1 addition & 0 deletions packages/common-app/src/helpers/i18n/dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const enLocale = [
['senddatatootheridentitiesonmybehalf', 'Send data to other identities on my behalf'],
['writer', 'Write'],
['writereactionsandcomments', 'Write Reactions and Comments'],
['sendpushnotifications', 'Send Push Notifications'],
] as const;

const internalDict: Map<string, string> = new Map(enLocale);
Expand Down
56 changes: 55 additions & 1 deletion packages/common-app/src/helpers/timeago/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,63 @@ import { Opts, TDate } from './interface';
* @param locale
* @param opts
*/
export const format = (date: TDate, locale = 'en_short', opts?: Opts): string => {
export const formatToTimeAgo = (date: TDate, locale = 'en_short', opts?: Opts): string => {
// diff seconds
const sec = diffSec(date, opts && opts.relativeDate);
// format it with locale
return formatDiff(sec, getLocale(locale));
};

export const formatToTimeAgoWithRelativeDetail = (
date: Date | undefined,
keepDetailWhenIncludesDate?: boolean
): string | undefined => {
if (!date) return undefined;

const oneHourAgo = new Date();
oneHourAgo.setHours(oneHourAgo.getHours() - 1);
if (date > oneHourAgo) return formatToTimeAgo(date).replaceAll('ago', '').replaceAll('just', '');

// if date is not today
const today = new Date();
today.setHours(0, 0, 0, 0);
if (date >= today) {
const timeFormat: Intl.DateTimeFormatOptions = {
hour: 'numeric',
minute: 'numeric',
};
return date.toLocaleTimeString(undefined, timeFormat);
}

// if date is this week
const thisWeek = new Date();
thisWeek.setDate(thisWeek.getDate() - thisWeek.getDay());
if (date >= thisWeek) {
const weekdayFormat: Intl.DateTimeFormatOptions = {
weekday: 'short',
};
return date.toLocaleDateString(undefined, weekdayFormat);
}

const now = new Date();
// if date is this month
const monthsAgo = Math.abs(now.getMonth() - date.getMonth());
if (monthsAgo === 0) {
const dayFormat: Intl.DateTimeFormatOptions = {
day: 'numeric',
month: 'short',
};
return date.toLocaleDateString(undefined, dayFormat);
}

// if date not this month..
const yearsAgo = Math.abs(new Date(now.getTime() - date.getTime()).getUTCFullYear() - 1970);
const dateTimeFormat: Intl.DateTimeFormatOptions = {
month: keepDetailWhenIncludesDate ? 'short' : 'numeric',
day: 'numeric',
year: yearsAgo !== 0 ? 'numeric' : undefined,
hour: keepDetailWhenIncludesDate ? 'numeric' : undefined,
minute: keepDetailWhenIncludesDate ? 'numeric' : undefined,
};
return date.toLocaleDateString(undefined, dateTimeFormat);
};
2 changes: 1 addition & 1 deletion packages/common-app/src/helpers/timeago/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { format } from './format';
export { formatToTimeAgo } from './format';
87 changes: 3 additions & 84 deletions packages/common-app/src/hooks/errors/useErrors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,90 +6,9 @@ export interface Error {
message: string;
}

const getKnownErrorMessages = (errorCode: number): string | undefined => {
if (errorCode) {
switch (errorCode) {
case 1001:
return t('InvalidAuthToken');
case 2001:
return t('InvalidNotificationType');
case 2002:
return t('UnknownNotificationId');
case 3001:
return t('A circle cannot have no permissions, please review and try again');
case 3002:
return t('CannotAllowCirclesOnAuthenticatedOnly');
case 3003:
return t('CannotAllowCirclesOrIdentitiesOnAnonymousOrOwnerOnly');
case 3004:
return t('CannotDeleteCircleWithMembers');
case 3005:
return t('IdentityAlreadyMemberOfCircle');
case 3006:
return t('NotAConnectedIdentity');
case 4001:
return t('CannotAllowAnonymousReadsOnOwnerOnlyDrive');
case 4002:
return t('CannotUpdateDeletedFile');
case 4003:
return t('DriveAliasAndTypeAlreadyExists');
case 4004:
return t('InvalidGrantNonExistingDrive');
case 4101:
return t('CannotOverwriteNonExistentFileStef');
case 4102:
return t('CannotUploadEncryptedFileForAnonymous');
case 4103:
return t('CannotUseGlobalTransitIdOnTransientFile');
case 4104:
return t('DriveSecurityAndAclMismatch');
case 4105:
return t('ExistingFileWithUniqueId');
case 4106:
return t('FileNotFound');
case 4107:
return t('IdAlreadyExists');
case 4108:
return t('InvalidInstructionSet');
case 4109:
return t('InvalidKeyHeader');
case 4110:
return t('InvalidRecipient');
case 4111:
return t('InvalidTargetDrive');
case 4112:
return t('InvalidThumnbnailName');
case 4113:
return t('InvalidTransferFileType');
case 4114:
return t('InvalidTransferType');
case 4115:
return t('MalformedMetadata');
case 4116:
return t('MissingUploadData');
case 4117:
return t('TransferTypeNotSpecified');
case 4118:
return t('UnknownId');
case 5001:
return t('CannotSendConnectionRequestToExistingIncomingRequest');
case 5002:
return t('CannotSendMultipleConnectionRequestToTheSameIdentity');
case 5003:
return t('You cannot send a connection request to yourself');
case 6001:
return t('AppNotRegistered');
case 9001:
return t('InvalidFlagName');
case 9002:
return t('NotInitialized');
case 9003:
return t('UnknownFlagName');
}

console.log('Error code found, but no corresponding message in the dictionary', errorCode);
}
return;
const getKnownErrorMessages = (errorCode: string): string | undefined => {
// TODO: Can be extended with more user friendly error messages
return errorCode;
};

export const useErrors = () => {
Expand Down
43 changes: 19 additions & 24 deletions packages/common-app/src/hooks/notifications/useNotifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ import {
} from '@youfoundation/js-lib/core';
import { ReactNode, useState } from 'react';

import {
DomainHighlighter,
t,
useNotificationSubscriber,
usePendingConnections,
} from '@youfoundation/common-app';
import { DomainHighlighter, t, useNotificationSubscriber } from '@youfoundation/common-app';
import { useQueryClient } from '@tanstack/react-query';

interface Notification {
Expand All @@ -22,7 +17,7 @@ interface Notification {
}

export const useNotifications = () => {
const { data: pending } = usePendingConnections({ pageSize: 5, pageNumber: 1 }).fetch;
// const { data: pending } = usePendingConnections({ pageSize: 5, pageNumber: 1 }).fetch;
const [liveNotifications, setLiveNotifications] = useState<Notification[]>([]);
const queryClient = useQueryClient();

Expand Down Expand Up @@ -82,26 +77,26 @@ export const useNotifications = () => {
'unknown',
]);

const notifications = pending?.results.map((connection) => {
return {
key: `incoming-${connection.senderOdinId}`,
title: t('Incoming connection request'),
body: (
<>
{`${t('You have a new connection request from')}`}{' '}
<DomainHighlighter>{connection.senderOdinId}</DomainHighlighter>
</>
),
imgSrc: `https://${connection.senderOdinId}/pub/image`,
href: `/owner/connections/${connection.senderOdinId}`,
type: 'pending',
};
});
// const notifications = pending?.results.map((connection) => {
// return {
// key: `incoming-${connection.senderOdinId}`,
// title: t('Incoming connection request'),
// body: (
// <>
// {`${t('You have a new connection request from')}`}{' '}
// <DomainHighlighter>{connection.senderOdinId}</DomainHighlighter>
// </>
// ),
// imgSrc: `https://${connection.senderOdinId}/pub/image`,
// href: `/owner/connections/${connection.senderOdinId}`,
// type: 'pending',
// };
// });

return {
notifications,
// notifications,
liveNotifications,
hasUnread: notifications?.length ? notifications.length > 0 : false,
// hasUnread: notifications?.length ? notifications.length > 0 : false,
dismiss,
};
};
Loading

0 comments on commit 9e87730

Please sign in to comment.