diff --git a/apps/webapp/src/i18n/en-US.json b/apps/webapp/src/i18n/en-US.json index f9319f97ba3..3b020706739 100644 --- a/apps/webapp/src/i18n/en-US.json +++ b/apps/webapp/src/i18n/en-US.json @@ -713,6 +713,13 @@ "conversationFileUploadOverlayDescription": "Drag & drop to add files", "conversationFileUploadOverlayTitle": "Upload files", "conversationFileVideoPreviewLabel": "Video file preview for: {src}", + "conversationFilterDrafts": "Drafts", + "conversationFilterMentions": "Mentions", + "conversationFilterNone": "No filter", + "conversationFilterPings": "Pings", + "conversationFilterReplies": "Replies", + "conversationFilterTooltip": "Filter conversations", + "conversationFilterUnread": "Unread", "conversationFoldersEmptyText": "Add your conversations to folders to stay organized.", "conversationFoldersEmptyTextLearnMore": "Learn more", "conversationFooterArchive": "Archive", @@ -1843,6 +1850,8 @@ "selfNotSupportMLSMsgPart1": "You can't communicate with {selfUserName}, as your device doesn't support the suitable protocol.", "selfNotSupportMLSMsgPart2": "to call, and send messages and files.", "selfProfileImageAlt": "Your profile picture", + "servicesNotEnabledNoteTitle": "Your team doesn't use apps yet", + "servicesNotEnabledBody": "To improve your workflow with apps, your team needs configuration. Please contact your team admin.", "servicesOptionsTitle": "Apps", "servicesRoomToggleInfo": "Open this conversation to apps.", "servicesRoomToggleInfoExtended": "Open this conversation to apps. You can always change it later.", diff --git a/apps/webapp/src/script/components/Modals/CreateConversation/CreateConversationSteps/Preference.tsx b/apps/webapp/src/script/components/Modals/CreateConversation/CreateConversationSteps/Preference.tsx index b480d986535..1f4292411ce 100644 --- a/apps/webapp/src/script/components/Modals/CreateConversation/CreateConversationSteps/Preference.tsx +++ b/apps/webapp/src/script/components/Modals/CreateConversation/CreateConversationSteps/Preference.tsx @@ -20,6 +20,8 @@ import {CONVERSATION_PROTOCOL} from '@wireapp/api-client/lib/team'; import {container} from 'tsyringe'; +import {ConversationType} from 'Components/Modals/CreateConversation/types'; +import {AppsDisabledNote} from 'Components/Note/AppsDisabledNote/AppsDisabledNote'; import {InfoToggle} from 'Components/toggle/InfoToggle'; import {TeamState} from 'Repositories/team/TeamState'; import {Config} from 'src/script/Config'; @@ -27,7 +29,6 @@ import {useKoSubscribableChildren} from 'Util/ComponentUtil'; import {t} from 'Util/LocalizerUtil'; import {useCreateConversationModal} from '../hooks/useCreateConversationModal'; -import {ConversationType} from '../types'; export const Preference = () => { const { @@ -44,9 +45,16 @@ export const Preference = () => { const teamState = container.resolve(TeamState); - const {isCellsEnabled: isCellsEnabledForTeam, isMLSEnabled} = useKoSubscribableChildren(teamState, [ + const { + isCellsEnabled: isCellsEnabledForTeam, + isMLSEnabled, + isAppsEnabled, + hasWhitelistedServices, + } = useKoSubscribableChildren(teamState, [ 'isCellsEnabled', 'isMLSEnabled', + 'isAppsEnabled', + 'hasWhitelistedServices', ]); const isCellsEnabledForEnvironment = Config.getConfig().FEATURE.ENABLE_CELLS; const isCellsOptionEnabled = isCellsEnabledForEnvironment && isCellsEnabledForTeam; @@ -55,7 +63,13 @@ export const Preference = () => { ? teamState.teamFeatures()?.mls?.config.defaultProtocol : CONVERSATION_PROTOCOL.PROTEUS; - // Read receipts are temorarily disabled for MLS groups and channels until it is supported + const isAppsFeatureAvailable = + (defaultProtocol === CONVERSATION_PROTOCOL.MLS && isAppsEnabled) || + (defaultProtocol === CONVERSATION_PROTOCOL.PROTEUS && + hasWhitelistedServices && + conversationType !== ConversationType.Channel); + + // Read receipts are temporarily disabled for MLS groups and channels until it is supported const areReadReceiptsEnabled = defaultProtocol !== CONVERSATION_PROTOCOL.MLS; return ( @@ -70,17 +84,17 @@ export const Preference = () => { dataUieName="read-receipts" /> - {conversationType === ConversationType.Group && ( - - )} + } + /> + {areReadReceiptsEnabled && ( - {selectedProtocol.value !== CONVERSATION_PROTOCOL.MLS && ( - - )} + + + {!isAppsFeatureAvailable && } + {areReadReceiptsEnabled && ( { + return ( + + {t('servicesNotEnabledBody')} + + ); +}; + +export {AppsDisabledNote}; diff --git a/apps/webapp/src/script/components/Note/Note.styles.ts b/apps/webapp/src/script/components/Note/Note.styles.ts new file mode 100644 index 00000000000..7ded0083327 --- /dev/null +++ b/apps/webapp/src/script/components/Note/Note.styles.ts @@ -0,0 +1,49 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {CSSObject} from '@emotion/react'; + +export const ContainerStyle: CSSObject = { + display: 'flex', + flexDirection: 'column', + gap: '0.3rem', + padding: '0.75rem', + background: 'var(--accent-color-50)', + '.theme-dark &': { + background: 'var(--accent-color-800)', + boxShadow: 'none', + }, + border: '1px solid var(--accent-color-500)', + borderRadius: '0.5rem', + lineHeight: '1.5', + marginTop: '0.3rem', +}; + +export const HeaderStyle: CSSObject = { + display: 'flex', + alignItems: 'center', + fontWeight: 'var(--font-weight-semibold)', + gap: '0.5rem', +}; + +export const ContentStyle: CSSObject = { + display: 'flex', + flexDirection: 'column', + gap: '4px', +}; diff --git a/apps/webapp/src/script/components/Note/Note.tsx b/apps/webapp/src/script/components/Note/Note.tsx new file mode 100644 index 00000000000..d3add20369a --- /dev/null +++ b/apps/webapp/src/script/components/Note/Note.tsx @@ -0,0 +1,45 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import React, {ReactNode} from 'react'; + +import {InfoIcon} from 'Components/Icon'; +import {ContainerStyle, ContentStyle, HeaderStyle} from 'Components/Note/Note.styles'; + +interface NoteProps { + title: string; + children?: ReactNode; +} + +const Note = ({title, children}: NoteProps) => { + return ( +
+
+ + {title} +
+ +
+
{children}
+
+
+ ); +}; + +export {Note}; diff --git a/apps/webapp/src/script/components/toggle/InfoToggle.tsx b/apps/webapp/src/script/components/toggle/InfoToggle.tsx index 9f831d4ef04..41265ec002a 100644 --- a/apps/webapp/src/script/components/toggle/InfoToggle.tsx +++ b/apps/webapp/src/script/components/toggle/InfoToggle.tsx @@ -17,7 +17,7 @@ * */ -import {useId} from 'react'; +import React, {useId} from 'react'; import cx from 'classnames'; @@ -29,6 +29,7 @@ interface InfoToggleProps { name: string; className?: string; setIsChecked: (checked: boolean) => void; + label?: React.ReactNode; } const InfoToggle = ({ @@ -39,6 +40,7 @@ const InfoToggle = ({ isDisabled, name, setIsChecked, + label, }: InfoToggleProps) => { const dataUieNameInfoText = `status-info-toggle-${dataUieName}`; const dataUieNameLabelText = `do-toggle-${dataUieName}`; @@ -77,6 +79,7 @@ const InfoToggle = ({ + {label} ); }; diff --git a/apps/webapp/src/types/i18n.d.ts b/apps/webapp/src/types/i18n.d.ts index 25a858c12dd..b6b94385073 100644 --- a/apps/webapp/src/types/i18n.d.ts +++ b/apps/webapp/src/types/i18n.d.ts @@ -1798,6 +1798,7 @@ declare module 'I18n/en-US.json' { 'searchCreateGroup': `Create group`; 'searchCreateGuestRoom': `Create guest room`; 'searchDirectConversations': `Search 1:1 conversations`; + 'searchDraftsConversations': `Search in drafts`; 'searchFavoriteConversations': `Search favorites`; 'searchFederatedDomainNotAvailable': `The federated domain is currently not available.`; 'searchFederatedDomainNotAvailableLearnMore': `Learn more`; @@ -1816,6 +1817,7 @@ declare module 'I18n/en-US.json' { 'searchManageServices': `Manage Apps`; 'searchManageServicesNoResults': `Manage apps`; 'searchMemberInvite': `Invite people to join the team`; + 'searchMentionsConversations': `Search in mentions`; 'searchNoContactsOnWire': `You have no contacts on {brandName}.\nTry finding people by\nname or username.`; 'searchNoMatchesPartner': `No results`; 'searchNoServicesManager': `Apps are helpers that can improve your workflow.`; @@ -1826,6 +1828,8 @@ declare module 'I18n/en-US.json' { 'searchPeople': `People`; 'searchPeopleOnlyPlaceholder': `Search people`; 'searchPeoplePlaceholder': `Search for people and conversations`; + 'searchPingsConversations': `Search in pings`; + 'searchRepliesConversations': `Search in replies`; 'searchServiceConfirmButton': `Open Conversation`; 'searchServicePlaceholder': `Search by name`; 'searchServices': `Apps`; @@ -1835,6 +1839,7 @@ declare module 'I18n/en-US.json' { 'searchTrySearch': `Find people by\nname or username`; 'searchTrySearchFederation': `Find people in Wire by name or\n@username\n\nFind people from another domain\nby @username@domainname`; 'searchTrySearchLearnMore': `Learn more`; + 'searchUnreadConversations': `Search in unread`; 'selectAccountTypeHeading': `How will you use Wire?`; 'selectPersonalAccountTypeOptionButtonText': `Create Personal Account`; 'selectPersonalAccountTypeOptionDescription': `Chat with friends and family.`; @@ -1849,6 +1854,8 @@ declare module 'I18n/en-US.json' { 'selfNotSupportMLSMsgPart1': `You can\'t communicate with {selfUserName}, as your device doesn\'t support the suitable protocol.`; 'selfNotSupportMLSMsgPart2': `to call, and send messages and files.`; 'selfProfileImageAlt': `Your profile picture`; + 'servicesNotEnabledNoteTitle': `Your team doesn\'t use apps yet`; + 'servicesNotEnabledBody': `To improve your workflow with apps, your team needs configuration. Please contact your team admin.`; 'servicesOptionsTitle': `Apps`; 'servicesRoomToggleInfo': `Open this conversation to apps.`; 'servicesRoomToggleInfoExtended': `Open this conversation to apps. You can always change it later.`; @@ -1885,6 +1892,8 @@ declare module 'I18n/en-US.json' { 'success.openWebAppText': `Open Wire for web`; 'success.subheader': `What do you want to do next?`; 'systemMessageLearnMore': `Learn more`; + 'tabsFilterHeader': `Show filters`; + 'tabsFilterTooltip': `Customize visible tabs`; 'takeoverButtonChoose': `Choose your own`; 'takeoverButtonKeep': `Keep this one`; 'takeoverLink': `Learn more`;