diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index cafa1c320..9c6bca17d 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -590,6 +590,8 @@
"noMessagesInEverythingElse": "You have no messages from $name$. Send a message to start the conversation!",
"hideBanner": "Hide",
"someOfYourDeviceUseOutdatedVersion": "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.",
+ "versionRequiredForNewGroupDescription": "Users must have version {VERSION} or higher to receive invitations",
+ "upgradeYourGroupBefore": "Groups have been upgraded. Upgrade your group chats by creating a new Group. Support for old Groups will be discontinued on [Date].",
"openMessageRequestInboxDescription": "View your Message Request inbox",
"clearAllReactions": "Are you sure you want to clear all $emoji$ ?",
"expandedReactionsText": "Show Less",
diff --git a/ts/components/NoticeBanner.tsx b/ts/components/NoticeBanner.tsx
index 255926d82..592f113db 100644
--- a/ts/components/NoticeBanner.tsx
+++ b/ts/components/NoticeBanner.tsx
@@ -1,7 +1,8 @@
-import React from 'react';
+import React, { SessionDataTestId } from 'react';
import styled from 'styled-components';
import { Flex } from './basic/Flex';
-import { SessionIconButton } from './icon';
+import { SessionIconButton, SessionIconType } from './icon';
+import { StyledRootDialog } from './dialog/StyledRootDialog';
const StyledNoticeBanner = styled(Flex)`
position: relative;
@@ -23,11 +24,13 @@ const StyledText = styled.span`
type NoticeBannerProps = {
text: string;
- dismissCallback: () => void;
+ icon: SessionIconType;
+ onButtonClick: () => void;
+ dataTestId: SessionDataTestId;
};
export const NoticeBanner = (props: NoticeBannerProps) => {
- const { text, dismissCallback } = props;
+ const { text, onButtonClick, icon, dataTestId } = props;
return (
{
flexDirection={'row'}
justifyContent={'center'}
alignItems={'center'}
+ data-testid={dataTestId}
>
{text}
{
event?.preventDefault();
- dismissCallback();
+ onButtonClick();
}}
/>
);
};
+
+const StyledGroupInviteBanner = styled(Flex)`
+ position: relative;
+ background-color: var(--orange-color);
+ color: var(--black-color);
+ font-size: var(--font-size-sm);
+ padding: var(--margins-xs) var(--margins-lg);
+ text-align: center;
+ flex-shrink: 0;
+
+ // when part a a dialog, invert it and make it narrower (as the dialog grows to make it fit)
+ ${StyledRootDialog} & {
+ background-color: unset;
+ color: var(--orange-color);
+ max-width: 300px;
+ }
+`;
+
+export const GroupInviteRequiredVersionBanner = () => {
+ return (
+
+ {window.i18n('versionRequiredForNewGroupDescription')}
+
+ );
+};
diff --git a/ts/components/SessionInboxView.tsx b/ts/components/SessionInboxView.tsx
index bc69090b2..df3b0b78b 100644
--- a/ts/components/SessionInboxView.tsx
+++ b/ts/components/SessionInboxView.tsx
@@ -120,7 +120,9 @@ const SomeDeviceOutdatedSyncingNotice = () => {
return (
);
};
diff --git a/ts/components/SessionWrapperModal.tsx b/ts/components/SessionWrapperModal.tsx
index c75a64c0d..cf5a2cfe6 100644
--- a/ts/components/SessionWrapperModal.tsx
+++ b/ts/components/SessionWrapperModal.tsx
@@ -5,6 +5,7 @@ import useKey from 'react-use/lib/useKey';
import { SessionIconButton } from './icon';
import { SessionButton, SessionButtonColor, SessionButtonType } from './basic/SessionButton';
+import { StyledRootDialog } from './dialog/StyledRootDialog';
export type SessionWrapperModalType = {
title?: string;
@@ -63,7 +64,7 @@ export const SessionWrapperModal = (props: SessionWrapperModalType) => {
};
return (
-
{
-
+
);
};
diff --git a/ts/components/conversation/SessionConversation.tsx b/ts/components/conversation/SessionConversation.tsx
index df5128e6a..df9f157a2 100644
--- a/ts/components/conversation/SessionConversation.tsx
+++ b/ts/components/conversation/SessionConversation.tsx
@@ -251,26 +251,15 @@ export class SessionConversation extends React.Component {
// TODOLATER break selectionMode into it's own container component so we can use hooks to fetch relevant state from the store
const selectionMode = selectedMessages.length > 0;
- const bannerText =
- selectedConversation.hasOutdatedClient &&
- selectedConversation.hasOutdatedClient !== ourDisplayNameInProfile
- ? window.i18n('disappearingMessagesModeOutdated', [selectedConversation.hasOutdatedClient])
- : window.i18n('someOfYourDeviceUseOutdatedVersion');
-
return (
- {selectedConversation?.hasOutdatedClient?.length ? (
- {
- const conversation = ConvoHub.use().get(selectedConversation.id);
- conversation.set({ hasOutdatedClient: undefined });
- void conversation.commit();
- }}
- />
- ) : null}
+
+
{isSelectedConvoInitialLoadingInProgress ? (
@@ -652,3 +641,50 @@ const renderImagePreview = async (contentType: string, file: File, fileName: str
thumbnail: null,
};
};
+
+function OutdatedClientBanner(props: {
+ selectedConversation: Pick;
+ ourDisplayNameInProfile: string;
+}) {
+ const { selectedConversation, ourDisplayNameInProfile } = props;
+ const bannerText =
+ selectedConversation.hasOutdatedClient &&
+ selectedConversation.hasOutdatedClient !== ourDisplayNameInProfile
+ ? window.i18n('disappearingMessagesModeOutdated', [selectedConversation.hasOutdatedClient])
+ : window.i18n('someOfYourDeviceUseOutdatedVersion');
+
+ return selectedConversation.hasOutdatedClient?.length ? (
+ {
+ const conversation = ConvoHub.use().get(selectedConversation.id);
+ conversation.set({ hasOutdatedClient: undefined });
+ void conversation.commit();
+ }}
+ icon="exit"
+ dataTestId="some-of-your-devices-outdated-conversation"
+ />
+ ) : null;
+}
+
+function OutdatedLegacyGroupBanner(props: {
+ selectedConversation: Pick;
+}) {
+ const { selectedConversation } = props;
+
+ const isLegacyGroup =
+ !selectedConversation.isPrivate &&
+ !selectedConversation.isPublic &&
+ selectedConversation.id.startsWith('05');
+
+ return isLegacyGroup ? (
+ {
+ throw new Error('TODO'); // fixme audric
+ }}
+ icon="externalLink"
+ dataTestId="legacy-group-banner"
+ />
+ ) : null;
+}
diff --git a/ts/components/dialog/InviteContactsDialog.tsx b/ts/components/dialog/InviteContactsDialog.tsx
index 86bfd0ad3..6f80fac8e 100644
--- a/ts/components/dialog/InviteContactsDialog.tsx
+++ b/ts/components/dialog/InviteContactsDialog.tsx
@@ -31,6 +31,7 @@ import { SessionWrapperModal } from '../SessionWrapperModal';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
import { SessionSpinner } from '../basic/SessionSpinner';
import { SessionToggle } from '../basic/SessionToggle';
+import { GroupInviteRequiredVersionBanner } from '../NoticeBanner';
type Props = {
conversationId: string;
@@ -186,12 +187,16 @@ const InviteContactsDialogInner = (props: Props) => {
return (
+ {hasContacts && isGroupV2 && }
+
{isGroupV2 && (
-
- Share History?{' '}
- setShareHistory(!shareHistory)} />
-
+ <>
+
+ Share History?{' '}
+ setShareHistory(!shareHistory)} />
+
+ >
)}
{hasContacts ? (
diff --git a/ts/components/dialog/StyledRootDialog.tsx b/ts/components/dialog/StyledRootDialog.tsx
new file mode 100644
index 000000000..d98a95fae
--- /dev/null
+++ b/ts/components/dialog/StyledRootDialog.tsx
@@ -0,0 +1,3 @@
+import styled from 'styled-components';
+
+export const StyledRootDialog = styled.div``;
diff --git a/ts/components/leftpane/overlay/OverlayClosedGroup.tsx b/ts/components/leftpane/overlay/OverlayClosedGroup.tsx
index a5609094d..fe8db6d1b 100644
--- a/ts/components/leftpane/overlay/OverlayClosedGroup.tsx
+++ b/ts/components/leftpane/overlay/OverlayClosedGroup.tsx
@@ -23,6 +23,7 @@ import { getSearchResultsContactOnly, isSearching } from '../../../state/selecto
import { useOurPkStr } from '../../../state/selectors/user';
import { SessionSearchInput } from '../../SessionSearchInput';
import { SpacerLG } from '../../basic/Text';
+import { GroupInviteRequiredVersionBanner } from '../../NoticeBanner';
const StyledMemberListNoContacts = styled.div`
font-family: var(--font-mono), var(--font-default);
@@ -178,6 +179,10 @@ export const OverlayClosedGroupV2 = () => {
+ {!noContactsForClosedGroup && window.sessionFeatureFlags.useClosedGroupV2 && (
+
+ )}
+
{noContactsForClosedGroup ? (
diff --git a/ts/react.d.ts b/ts/react.d.ts
index ba47a8b34..92b76d5ea 100644
--- a/ts/react.d.ts
+++ b/ts/react.d.ts
@@ -51,6 +51,10 @@ declare module 'react' {
| 'microphone-button'
| 'call-button'
| 'attachments-button'
+ | 'invite-warning'
+ | 'some-of-your-devices-outdated-conversation'
+ | 'some-of-your-devices-outdated-inbox'
+ | 'legacy-group-banner'
// generic button types
| 'emoji-button'
diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts
index 458be881c..8bbc5a6b3 100644
--- a/ts/types/LocalizerKeys.ts
+++ b/ts/types/LocalizerKeys.ts
@@ -290,8 +290,8 @@ export type LocalizerKeys =
| 'leaveGroupConfirmation'
| 'leaveGroupConfirmationAdmin'
| 'leaveGroupConfirmationOnlyAdmin'
- | 'leaveGroupConfirmationOnlyAdminWarning'
| 'leaveGroupConfirmationOnlyAdminLegacy'
+ | 'leaveGroupConfirmationOnlyAdminWarning'
| 'leaveGroupFailed'
| 'leaveGroupFailedPleaseTryAgain'
| 'leaving'
@@ -575,6 +575,7 @@ export type LocalizerKeys =
| 'unreadMessages'
| 'updateDisappearingMessagesFallback'
| 'updateGroupDialogTitle'
+ | 'upgradeYourGroupBefore'
| 'userAddedToModerators'
| 'userBanFailed'
| 'userBanned'
@@ -582,6 +583,7 @@ export type LocalizerKeys =
| 'userRemovedFromModerators'
| 'userUnbanFailed'
| 'userUnbanned'
+ | 'versionRequiredForNewGroupDescription'
| 'video'
| 'videoAttachmentAlt'
| 'viewMenuResetZoom'