feat: mobile troubleshoot notifications (#5330)
* feat: troubleshoot notification (#5198) * navigation done * create the icon inside roomslistview, navigation to push troubleshot and layout push troubleshoot * custom header * fix the rooms list view header icon * layout done * update the pt-br i18n * tweak on colors * feat: create notification in room view (#5250) * button and simple navigation done, missing master detail * navigation * add withTheme and colors to rightuttons * fix e2e test * feat: add troubleshooting to notifications pages (#5276) * feat: add troubleshooting to notifications pages * fix e2e test * feat: device notification settings (#5277) * iOS go to device notification setting to change the configuration * go to notification settings with android * add notifee * add the reducer and action * saga request done * add the setInAlert action * tweak at name and add focus to dispatch the request * use the foreground inside pushTroubleShoot to request the notification and fix the icon color * add the request at roomslistview didmount * remove the notification modulo from android * add patch * minor tweak * feat: test push notification (#5329) * feat: test push notification * restApi and definition * push.info and change properly the troubleshootingNotification * use the finally at try/catch * minor tweak * alert and push.info just for 6.6 * fix the react-native.config * minor tweaks * minor tweak * push.test as rest api * change the name from inAlertNotification to highlightTroubleshooting * feat: push quota * refactor the percentage state * removed the push quota feature * minor tweaks * update the link to push notification * the notification icon in the room header will appear if notifications are disabled or highlight troubleshoot is true * remove push quota texts * updated some of the push quota texts * chore: rename highlightTroubleshooting * chore: better prop naming * wip * chore: fix function name * chore: fix colors * fix: copy * chore: 💅 * chore: use fork * chore: naming * chore: fix init * chore: naming * chore: naming * Comment CE code * Use put on troubleshooting saga * Add db column * fix: check notification payload * action: organized translations * fix: push init --------- Co-authored-by: GleidsonDaniel <gleidson10daniel@hotmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> Co-authored-by: GleidsonDaniel <GleidsonDaniel@users.noreply.github.com>
This commit is contained in:
parent
eefb8793a5
commit
4c8caf0bfd
|
@ -96,5 +96,6 @@ export const VIDEO_CONF = createRequestTypes('VIDEO_CONF', [
|
|||
'ACCEPT_CALL',
|
||||
'SET_CALLING'
|
||||
]);
|
||||
export const TROUBLESHOOTING_NOTIFICATION = createRequestTypes('TROUBLESHOOTING_NOTIFICATION', ['INIT', 'SET']);
|
||||
export const SUPPORTED_VERSIONS = createRequestTypes('SUPPORTED_VERSIONS', ['SET']);
|
||||
export const IN_APP_FEEDBACK = createRequestTypes('IN_APP_FEEDBACK', ['SET', 'REMOVE', 'CLEAR']);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import { Action } from 'redux';
|
||||
|
||||
import { TROUBLESHOOTING_NOTIFICATION } from './actionsTypes';
|
||||
import { ITroubleshootingNotification } from '../reducers/troubleshootingNotification';
|
||||
|
||||
type TSetTroubleshootingNotification = Action & { payload: Partial<ITroubleshootingNotification> };
|
||||
|
||||
export type TActionTroubleshootingNotification = Action & TSetTroubleshootingNotification;
|
||||
|
||||
export function initTroubleshootingNotification(): Action {
|
||||
return {
|
||||
type: TROUBLESHOOTING_NOTIFICATION.INIT
|
||||
};
|
||||
}
|
||||
|
||||
export function setTroubleshootingNotification(payload: Partial<ITroubleshootingNotification>): TSetTroubleshootingNotification {
|
||||
return {
|
||||
type: TROUBLESHOOTING_NOTIFICATION.SET,
|
||||
payload
|
||||
};
|
||||
}
|
|
@ -36,7 +36,7 @@ export const VideoConferenceBaseContainer = ({ variant, children }: VideoConfMes
|
|||
},
|
||||
issue: {
|
||||
icon: 'phone-issue',
|
||||
color: colors.statusFontOnWarning,
|
||||
color: colors.statusFontWarning,
|
||||
backgroundColor: colors.statusBackgroundWarning,
|
||||
label: i18n.t('Call_issue')
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ export interface ISubscription {
|
|||
threads: RelationModified<TThreadModel>;
|
||||
threadMessages: RelationModified<TThreadMessageModel>;
|
||||
uploads: RelationModified<TUploadModel>;
|
||||
disableNotifications?: boolean;
|
||||
}
|
||||
|
||||
export type TSubscriptionModel = ISubscription &
|
||||
|
|
|
@ -40,6 +40,8 @@ import { IEnterpriseModules } from '../../reducers/enterpriseModules';
|
|||
import { IVideoConf } from '../../reducers/videoConf';
|
||||
import { TActionUsersRoles } from '../../actions/usersRoles';
|
||||
import { TUsersRoles } from '../../reducers/usersRoles';
|
||||
import { ITroubleshootingNotification } from '../../reducers/troubleshootingNotification';
|
||||
import { TActionTroubleshootingNotification } from '../../actions/troubleshootingNotification';
|
||||
import { ISupportedVersionsState } from '../../reducers/supportedVersions';
|
||||
import { IInAppFeedbackState } from '../../reducers/inAppFeedback';
|
||||
|
||||
|
@ -67,6 +69,7 @@ export interface IApplicationState {
|
|||
roles: IRoles;
|
||||
videoConf: IVideoConf;
|
||||
usersRoles: TUsersRoles;
|
||||
troubleshootingNotification: ITroubleshootingNotification;
|
||||
supportedVersions: ISupportedVersionsState;
|
||||
inAppFeedback: IInAppFeedbackState;
|
||||
}
|
||||
|
@ -90,5 +93,6 @@ export type TApplicationActions = TActionActiveUsers &
|
|||
TActionEnterpriseModules &
|
||||
TActionVideoConf &
|
||||
TActionUsersRoles &
|
||||
TActionTroubleshootingNotification &
|
||||
TActionSupportedVersions &
|
||||
TInAppFeedbackAction;
|
||||
|
|
|
@ -17,7 +17,7 @@ import { E2eEndpoints } from './e2e';
|
|||
import { SubscriptionsEndpoints } from './subscriptions';
|
||||
import { VideoConferenceEndpoints } from './videoConference';
|
||||
import { CommandsEndpoints } from './commands';
|
||||
import { PushTokenEndpoints } from './pushToken';
|
||||
import { PushEndpoints } from './push';
|
||||
import { DirectoryEndpoint } from './directory';
|
||||
import { AutoTranslateEndpoints } from './autotranslate';
|
||||
import { ModerationEndpoints } from './moderation';
|
||||
|
@ -41,7 +41,7 @@ export type Endpoints = ChannelsEndpoints &
|
|||
SubscriptionsEndpoints &
|
||||
VideoConferenceEndpoints &
|
||||
CommandsEndpoints &
|
||||
PushTokenEndpoints &
|
||||
PushEndpoints &
|
||||
DirectoryEndpoint &
|
||||
AutoTranslateEndpoints &
|
||||
ModerationEndpoints;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
type TPushInfo = {
|
||||
pushGatewayEnabled: boolean;
|
||||
defaultPushGateway: boolean;
|
||||
success: boolean;
|
||||
};
|
||||
|
||||
export type PushEndpoints = {
|
||||
'push.token': {
|
||||
POST: (params: { value: string; type: string; appName: string }) => {
|
||||
result: {
|
||||
id: string;
|
||||
token: string;
|
||||
appName: string;
|
||||
userId: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
'push.info': {
|
||||
GET: () => TPushInfo;
|
||||
};
|
||||
'push.test': {
|
||||
POST: () => { tokensCount: number };
|
||||
};
|
||||
};
|
|
@ -1,12 +0,0 @@
|
|||
export type PushTokenEndpoints = {
|
||||
'push.token': {
|
||||
POST: (params: { value: string; type: string; appName: string }) => {
|
||||
result: {
|
||||
id: string;
|
||||
token: string;
|
||||
appName: string;
|
||||
userId: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -24,6 +24,7 @@
|
|||
"All_users_in_the_channel_can_write_new_messages": "All users in the channel can write new messages",
|
||||
"All_users_in_the_team_can_write_new_messages": "All users in the team can write new messages",
|
||||
"Allow_Reactions": "Allow reactions",
|
||||
"Allow_push_notifications_for_rocket_chat": "Allow push notifications for Rocket.Chat",
|
||||
"Also_send_thread_message_to_channel_behavior": "Also send thread message to channel",
|
||||
"Announcement": "Announcement",
|
||||
"App_users_are_not_allowed_to_log_in_directly": "App users are not allowed to log in directly.",
|
||||
|
@ -102,6 +103,7 @@
|
|||
"Code_block": "Code block",
|
||||
"Code_or_password_invalid": "Code or password invalid",
|
||||
"Collaborative": "Collaborative",
|
||||
"Community_edition_push_quota": "Community push quota",
|
||||
"Condensed": "Condensed",
|
||||
"Confirm": "Confirm",
|
||||
"Confirmation": "Confirmation",
|
||||
|
@ -134,6 +136,8 @@
|
|||
"Create_a_new_workspace": "Create a new workspace",
|
||||
"Create_account": "Create an account",
|
||||
"Created_snippet": "created a snippet",
|
||||
"Custom_push_gateway_connected_description": "Your workspace uses a custom push notification gateway. Check with your workspace administrator for any issues.",
|
||||
"Custom_push_gateway_connection": "Custom Gateway Connection",
|
||||
"DELETE": "DELETE",
|
||||
"Dark": "Dark",
|
||||
"Dark_level": "Dark level",
|
||||
|
@ -156,6 +160,9 @@
|
|||
"Description": "Description",
|
||||
"Desktop_Alert_info": "These notifications are delivered in desktop",
|
||||
"Desktop_Notifications": "Desktop notifications",
|
||||
"Device_notification_settings": "Device notification settings",
|
||||
"Device_notifications_alert_description": "Please go to your settings app and enable notifications for Rocket.Chat",
|
||||
"Device_notifications_alert_title": "Notifications disabled",
|
||||
"Direct_Messages": "Direct messages",
|
||||
"Direct_message": "Direct message",
|
||||
"Direct_message_someone": "Direct message someone",
|
||||
|
@ -174,6 +181,7 @@
|
|||
"Do_you_have_a_certificate": "Do you have a certificate?",
|
||||
"Do_you_have_an_account": "Do you have an account?",
|
||||
"Do_you_really_want_to_key_this_room_question_mark": "Do you really want to {{key}} this room?",
|
||||
"Documentation": "Documentation",
|
||||
"Dont_Have_An_Account": "Don't you have an account?",
|
||||
"Dont_activate": "Don't activate now",
|
||||
"Downloaded_file": "Downloaded file",
|
||||
|
@ -387,6 +395,7 @@
|
|||
"No_channels_in_team": "No Channels on this team",
|
||||
"No_discussions": "No discussions",
|
||||
"No_files": "No files",
|
||||
"No_further_action_is_needed": "No further action is needed",
|
||||
"No_label_provided": "No {{label}} provided.",
|
||||
"No_limit": "No limit",
|
||||
"No_match_found": "No match found.",
|
||||
|
@ -404,6 +413,8 @@
|
|||
"Nothing": "Nothing",
|
||||
"Nothing_to_save": "Nothing to save!",
|
||||
"Notification_Preferences": "Notification preferences",
|
||||
"Notification_delay": "Notification delay",
|
||||
"Notification_delay_description": "There are factors that can contribute to delayed notifications. Learn more in Rocket.Chat's docs.",
|
||||
"Notifications": "Notifications",
|
||||
"Notify_active_in_this_room": "Notify active users in this room",
|
||||
"Notify_all_in_this_room": "Notify all in this room",
|
||||
|
@ -461,6 +472,10 @@
|
|||
"Public": "Public",
|
||||
"Push_Notifications": "Push notifications",
|
||||
"Push_Notifications_Alert_Info": "These notifications are delivered to you when the app is not open",
|
||||
"Push_Troubleshooting": "Push Troubleshooting",
|
||||
"Push_gateway_connected_description": "Send a push notification to yourself to check if the gateway is working",
|
||||
"Push_gateway_connection": "Push Gateway Connection",
|
||||
"Push_gateway_not_connected_description": "We're not able to connect to the push gateway. If this issue persists please check with your workspace administrator.",
|
||||
"Queued_chats": "Queued chats",
|
||||
"Quote": "Quote",
|
||||
"RESET": "RESET",
|
||||
|
@ -605,6 +620,7 @@
|
|||
"Team_not_found": "Team not found",
|
||||
"Teams": "Teams",
|
||||
"Terms_of_Service": " Terms of service ",
|
||||
"Test_push_notification": "Test push notification",
|
||||
"The_maximum_number_of_users_has_been_reached": "The maximum number of users has been reached.",
|
||||
"The_room_does_not_exist": "The room does not exist or you may not have access permission",
|
||||
"The_user_will_be_able_to_type_in_roomName": "The user will be able to type in {{roomName}}",
|
||||
|
@ -625,6 +641,7 @@
|
|||
"Token_expired": "Your session has expired. Please log in again.",
|
||||
"Topic": "Topic",
|
||||
"Translate": "Translate",
|
||||
"Troubleshooting": "Troubleshooting",
|
||||
"Try_again": "Try again",
|
||||
"Two_Factor_Authentication": "Two-factor authentication",
|
||||
"Type_message": "Type message",
|
||||
|
@ -690,6 +707,8 @@
|
|||
"Wi_Fi_and_mobile_data": "Wi-Fi and mobile data",
|
||||
"Without_Servers": "Without workspaces",
|
||||
"Workspace_URL_Example": "Ex. your-company.rocket.chat",
|
||||
"Workspace_consumption": "Workspace consumption",
|
||||
"Workspace_consumption_description": "There’s a set amount of push notifications per month",
|
||||
"Workspaces": "Workspaces",
|
||||
"Would_like_to_place_on_hold": "Would you like to place this chat on hold?",
|
||||
"Would_you_like_to_return_the_inquiry": "Would you like to return the inquiry?",
|
||||
|
@ -720,6 +739,7 @@
|
|||
"Your_invite_link_will_expire_on__date__or_after__usesLeft__uses": "Your invite link will expire on {{date}} or after {{usesLeft}} uses.",
|
||||
"Your_invite_link_will_never_expire": "Your invite link will never expire.",
|
||||
"Your_password_is": "Your password is",
|
||||
"Your_push_was_sent_to_s_devices": "Your push was sent to {{s}} devices",
|
||||
"Your_workspace": "Your workspace",
|
||||
"__count__empty_room_will_be_removed_automatically": "{{count}} empty room will be deleted.",
|
||||
"__count__empty_rooms_will_be_removed_automatically": "{{count}} empty rooms will be deleted.",
|
||||
|
@ -761,6 +781,7 @@
|
|||
"error-invalid-file-type": "Invalid file type",
|
||||
"error-invalid-password": "Invalid password",
|
||||
"error-invalid-room-name": "{{room_name}} is not a valid room name",
|
||||
"error-no-tokens-for-this-user": "There are no tokens for this user",
|
||||
"error-not-allowed": "Not allowed",
|
||||
"error-not-permission-to-upload-file": "You don't have permission to upload files",
|
||||
"error-save-image": "Error while saving image",
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"All_users_in_the_channel_can_write_new_messages": "Todos usuários no canal podem enviar mensagens novas",
|
||||
"All_users_in_the_team_can_write_new_messages": "Todos usuários no canal podem enviar mensagens novas",
|
||||
"Allow_Reactions": "Permitir reagir",
|
||||
"Allow_push_notifications_for_rocket_chat": "Nenhuma ação adicional é necessária",
|
||||
"Also_send_thread_message_to_channel_behavior": "Também enviar mensagem do tópico para o canal",
|
||||
"Announcement": "Anúncio",
|
||||
"App_users_are_not_allowed_to_log_in_directly": "Usuários do aplicativo não estão autorizados a fazer login diretamente.",
|
||||
|
@ -55,7 +56,7 @@
|
|||
"Call_issue": "Chamada com problemas",
|
||||
"Call_ongoing": "Chamada em andamento",
|
||||
"Call_rejected": "Chamada rejeitada",
|
||||
"Call_started": "Chamada iniciada",
|
||||
"Call_started": "Chamada Iniciada",
|
||||
"Call_was_not_answered": "A chamada não foi atendida",
|
||||
"Calling": "Chamando",
|
||||
"Cancel": "Cancelar",
|
||||
|
@ -99,6 +100,7 @@
|
|||
"Close_emoji_selector": "Fechar seletor de emojis",
|
||||
"Code_or_password_invalid": "Código ou senha inválido",
|
||||
"Collaborative": "Colaborativo",
|
||||
"Community_edition_push_quota": "Cota de notificações push Community Edition",
|
||||
"Condensed": "Condensado",
|
||||
"Confirm": "Confirmar",
|
||||
"Confirmation": "Confirmação",
|
||||
|
@ -131,6 +133,8 @@
|
|||
"Create_a_new_workspace": "Criar nova área de trabalho",
|
||||
"Create_account": "Criar conta",
|
||||
"Created_snippet": "criou um snippet",
|
||||
"Custom_push_gateway_connected_description": "Seu workspace utiliza um gateway de notificação push personalizado. Verifique com o administrador do seu workspace se há algum problema.",
|
||||
"Custom_push_gateway_connection": "Conexão Personalizada com o Gateway",
|
||||
"DELETE": "EXCLUIR",
|
||||
"Dark": "Escuro",
|
||||
"Dark_level": "Nível escuro",
|
||||
|
@ -153,6 +157,9 @@
|
|||
"Description": "Descrição",
|
||||
"Desktop_Alert_info": "Essas notificações são entregues a você na área de trabalho",
|
||||
"Desktop_Notifications": "Notificações da área de trabalho",
|
||||
"Device_notification_settings": "Configurações de notificações do dispositivo",
|
||||
"Device_notifications_alert_description": "Por favor, vá para o aplicativo de configurações e habilite as notificações para o Rocket.Chat.",
|
||||
"Device_notifications_alert_title": "Notificações desativadas",
|
||||
"Direct_Messages": "Mensagens diretas",
|
||||
"Direct_message": "Mensagem direta",
|
||||
"Direct_message_someone": "Enviar mensagem direta para alguém",
|
||||
|
@ -171,6 +178,7 @@
|
|||
"Do_you_have_a_certificate": "Você tem um certificado?",
|
||||
"Do_you_have_an_account": "Você tem uma conta?",
|
||||
"Do_you_really_want_to_key_this_room_question_mark": "Você quer realmente {{key}} esta sala?",
|
||||
"Documentation": "Documentação",
|
||||
"Dont_Have_An_Account": "Não tem uma conta?",
|
||||
"Dont_activate": "Não ativar agora",
|
||||
"Downloaded_file": "Arquivo baixado",
|
||||
|
@ -267,6 +275,7 @@
|
|||
"Jitsi_authentication_before_making_calls_admin": "Jitsi pode exigir autenticação antes de fazer chamadas. Para saber mais sobre as políticas deles, visite o site do Jitsi. Você também pode atualizar o aplicativo padrão para chamadas de vídeo nas preferências.",
|
||||
"Jitsi_authentication_before_making_calls_ask_admin": "Se você acredita que há problemas com o Jitsi e sua autenticação, peça ajuda a um administrador do espaço de trabalho.",
|
||||
"Jitsi_may_require_authentication": "O Jitsi pode exigir autenticação",
|
||||
"Jitsi_may_requires_authentication": "Jitsi pode exigir autenticação",
|
||||
"Join": "Entrar",
|
||||
"Join_Code": "Insira o código da sala",
|
||||
"Join_our_open_workspace": "Entrar na nossa workspace pública",
|
||||
|
@ -381,6 +390,7 @@
|
|||
"No_channels_in_team": "Nenhum canal nesta equipe",
|
||||
"No_discussions": "Sem discussões",
|
||||
"No_files": "Não há arquivos",
|
||||
"No_further_action_is_needed": "Ir para configurações do dispositivo",
|
||||
"No_label_provided": "Sem {{label}}.",
|
||||
"No_limit": "Sem limite",
|
||||
"No_match_found": "Nenhum resultado encontrado.",
|
||||
|
@ -397,6 +407,8 @@
|
|||
"Nothing": "Nada",
|
||||
"Nothing_to_save": "Nada para salvar!",
|
||||
"Notification_Preferences": "Preferências de notificação",
|
||||
"Notification_delay": "Atraso de notificação",
|
||||
"Notification_delay_description": "Existem fatores que podem contribuir para atrasos nas notificações. Saiba mais na documentação do Rocket.Chat.",
|
||||
"Notifications": "Notificações",
|
||||
"Notify_active_in_this_room": "Notificar usuários ativos nesta sala",
|
||||
"Notify_all_in_this_room": "Notificar todos nesta sala",
|
||||
|
@ -452,6 +464,10 @@
|
|||
"Public": "Público",
|
||||
"Push_Notifications": "Notificações push",
|
||||
"Push_Notifications_Alert_Info": "Essas notificações são entregues a você quando o aplicativo não está aberto",
|
||||
"Push_Troubleshooting": "Solucionar Problemas de Push",
|
||||
"Push_gateway_connected_description": "Envie uma notificação push para si mesmo para verificar se o gateway está funcionando.",
|
||||
"Push_gateway_connection": "Conexão com o Gateway de Push",
|
||||
"Push_gateway_not_connected_description": "Não conseguimos conectar ao gateway de push. Se esse problema persistir, por favor, verifique com o administrador do seu workspace.",
|
||||
"Queued_chats": "Bate-papos na fila",
|
||||
"Quote": "Citar",
|
||||
"RESET": "RESETAR",
|
||||
|
@ -593,6 +609,7 @@
|
|||
"Team_not_found": "Time não encontrado",
|
||||
"Teams": "Times",
|
||||
"Terms_of_Service": " Termos de serviço ",
|
||||
"Test_push_notification": "Testar notificação push",
|
||||
"The_maximum_number_of_users_has_been_reached": "O número máximo de usuários foi atingido.",
|
||||
"The_room_does_not_exist": "A sala não existe ou você pode não ter permissão de acesso",
|
||||
"The_user_will_be_able_to_type_in_roomName": "O usuário poderá digitar em {{roomName}}",
|
||||
|
@ -678,6 +695,8 @@
|
|||
"Wi_Fi_and_mobile_data": "Wi-Fi e dados móveis",
|
||||
"Without_Servers": "Sem workspaces",
|
||||
"Workspace_URL_Example": "Ex. sua-empresa.rocket.chat",
|
||||
"Workspace_consumption": "Consumo do Workspace",
|
||||
"Workspace_consumption_description": "Existe uma quantidade definida de notificações push por mês",
|
||||
"Workspaces": "Workspaces",
|
||||
"Would_like_to_place_on_hold": "Gostaria de colocar essa conversa em espera?",
|
||||
"Would_you_like_to_return_the_inquiry": "Deseja retornar a consulta?",
|
||||
|
@ -708,6 +727,7 @@
|
|||
"Your_invite_link_will_expire_on__date__or_after__usesLeft__uses": "Seu link de convite irá vencer em {{date}} ou depois de {{usesLeft}} usos.",
|
||||
"Your_invite_link_will_never_expire": "Seu link de convite nunca irá vencer.",
|
||||
"Your_password_is": "Sua senha é",
|
||||
"Your_push_was_sent_to_s_devices": "A sua notificação foi enviada para {{s}} dispositivos",
|
||||
"Your_workspace": "Sua workspace",
|
||||
"__count__empty_room_will_be_removed_automatically": "{{count}} sala vazia será excluída.",
|
||||
"__count__empty_rooms_will_be_removed_automatically": "{{count}} salas vazias serão excluídas.",
|
||||
|
@ -749,6 +769,7 @@
|
|||
"error-invalid-file-type": "Tipo de arquivo inválido",
|
||||
"error-invalid-password": "Senha inválida",
|
||||
"error-invalid-room-name": "{{room_name}} não é um nome de sala válido",
|
||||
"error-no-tokens-for-this-user": "Não existem tokens para este usuário",
|
||||
"error-not-allowed": "Não permitido",
|
||||
"error-not-permission-to-upload-file": "Você não tem permissão para enviar arquivos",
|
||||
"error-save-image": "Erro ao salvar imagem",
|
||||
|
|
|
@ -287,7 +287,6 @@ export const colors = {
|
|||
gray100: '#CBCED1',
|
||||
n900: '#1F2329',
|
||||
statusBackgroundWarning: '#FFECAD',
|
||||
statusFontOnWarning: '#B88D00',
|
||||
overlayColor: '#1F2329CC',
|
||||
taskBoxColor: '#9297a2',
|
||||
...mentions,
|
||||
|
@ -369,7 +368,6 @@ export const colors = {
|
|||
gray100: '#CBCED1',
|
||||
n900: '#FFFFFF',
|
||||
statusBackgroundWarning: '#FFECAD',
|
||||
statusFontOnWarning: '#B88D00',
|
||||
overlayColor: '#1F2329CC',
|
||||
taskBoxColor: '#9297a2',
|
||||
...mentions,
|
||||
|
@ -451,7 +449,6 @@ export const colors = {
|
|||
gray100: '#CBCED1',
|
||||
n900: '#FFFFFF',
|
||||
statusBackgroundWarning: '#FFECAD',
|
||||
statusFontOnWarning: '#B88D00',
|
||||
overlayColor: '#1F2329CC',
|
||||
taskBoxColor: '#9297a2',
|
||||
...mentions,
|
||||
|
|
|
@ -145,6 +145,8 @@ export default class Subscription extends Model {
|
|||
|
||||
@json('source', sanitizer) source;
|
||||
|
||||
@field('disable_notifications') disableNotifications;
|
||||
|
||||
asPlain() {
|
||||
return {
|
||||
_id: this._id,
|
||||
|
@ -207,7 +209,8 @@ export default class Subscription extends Model {
|
|||
teamMain: this.teamMain,
|
||||
onHold: this.onHold,
|
||||
usersCount: this.usersCount,
|
||||
source: this.source
|
||||
source: this.source,
|
||||
disableNotifications: this.disableNotifications
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -284,6 +284,15 @@ export default schemaMigrations({
|
|||
columns: [{ name: 'unmuted', type: 'string', isOptional: true }]
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
toVersion: 24,
|
||||
steps: [
|
||||
addColumns({
|
||||
table: 'subscriptions',
|
||||
columns: [{ name: 'disable_notifications', type: 'boolean', isOptional: true }]
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { appSchema, tableSchema } from '@nozbe/watermelondb';
|
||||
|
||||
export default appSchema({
|
||||
version: 23,
|
||||
version: 24,
|
||||
tables: [
|
||||
tableSchema({
|
||||
name: 'subscriptions',
|
||||
|
@ -66,7 +66,8 @@ export default appSchema({
|
|||
{ name: 'source', type: 'string', isOptional: true },
|
||||
{ name: 'hide_mention_status', type: 'boolean', isOptional: true },
|
||||
{ name: 'users_count', type: 'number', isOptional: true },
|
||||
{ name: 'unmuted', type: 'string', isOptional: true }
|
||||
{ name: 'unmuted', type: 'string', isOptional: true },
|
||||
{ name: 'disable_notifications', type: 'boolean', isOptional: true }
|
||||
]
|
||||
}),
|
||||
tableSchema({
|
||||
|
|
|
@ -60,7 +60,8 @@ export const SUPPORTED_PERMISSIONS = [
|
|||
'view-canned-responses',
|
||||
'mobile-upload-file',
|
||||
'delete-own-message',
|
||||
'call-management'
|
||||
'call-management',
|
||||
'test-push-notifications'
|
||||
] as const;
|
||||
|
||||
export async function setPermissions(): Promise<void> {
|
||||
|
|
|
@ -5,12 +5,17 @@ import I18n from '../../../i18n';
|
|||
export const showErrorAlert = (message: string, title?: string, onPress = () => {}): void =>
|
||||
Alert.alert(title || '', message, [{ text: 'OK', onPress }], { cancelable: true });
|
||||
|
||||
export const showErrorAlertWithEMessage = (e: any): void => {
|
||||
const messageError =
|
||||
e.data && e.data.error.includes('[error-too-many-requests]')
|
||||
? I18n.t('error-too-many-requests', { seconds: e.data.error.replace(/\D/g, '') })
|
||||
: e.data.errorType;
|
||||
showErrorAlert(messageError);
|
||||
export const showErrorAlertWithEMessage = (e: any, title?: string): void => {
|
||||
let errorMessage: string = e?.data?.error;
|
||||
|
||||
if (errorMessage.includes('[error-too-many-requests]')) {
|
||||
const seconds = errorMessage.replace(/\D/g, '');
|
||||
errorMessage = I18n.t('error-too-many-requests', { seconds });
|
||||
} else {
|
||||
errorMessage = I18n.isTranslated(errorMessage) ? I18n.t(errorMessage) : errorMessage;
|
||||
}
|
||||
|
||||
showErrorAlert(errorMessage, title);
|
||||
};
|
||||
|
||||
interface IShowConfirmationAlert {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import EJSON from 'ejson';
|
||||
|
||||
import { appInit } from '../../actions/app';
|
||||
import { deepLinkingClickCallPush, deepLinkingOpen } from '../../actions/deepLinking';
|
||||
import { INotification, SubscriptionType } from '../../definitions';
|
||||
import { isFDroidBuild } from '../constants';
|
||||
|
@ -18,39 +19,43 @@ interface IEjson {
|
|||
export const onNotification = (push: INotification): void => {
|
||||
const identifier = String(push?.payload?.action?.identifier);
|
||||
if (identifier === 'ACCEPT_ACTION' || identifier === 'DECLINE_ACTION') {
|
||||
if (push.payload) {
|
||||
const notification = EJSON.parse(push.payload.ejson);
|
||||
if (push?.payload && push?.payload?.ejson) {
|
||||
const notification = EJSON.parse(push?.payload?.ejson);
|
||||
store.dispatch(deepLinkingClickCallPush({ ...notification, event: identifier === 'ACCEPT_ACTION' ? 'accept' : 'decline' }));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (push.payload) {
|
||||
if (push?.payload) {
|
||||
try {
|
||||
const notification = push.payload;
|
||||
const { rid, name, sender, type, host, messageId }: IEjson = EJSON.parse(notification.ejson);
|
||||
const notification = push?.payload;
|
||||
if (notification.ejson) {
|
||||
const { rid, name, sender, type, host, messageId }: IEjson = EJSON.parse(notification.ejson);
|
||||
|
||||
const types: Record<string, string> = {
|
||||
c: 'channel',
|
||||
d: 'direct',
|
||||
p: 'group',
|
||||
l: 'channels'
|
||||
};
|
||||
let roomName = type === SubscriptionType.DIRECT ? sender.username : name;
|
||||
if (type === SubscriptionType.OMNICHANNEL) {
|
||||
roomName = sender.name;
|
||||
const types: Record<string, string> = {
|
||||
c: 'channel',
|
||||
d: 'direct',
|
||||
p: 'group',
|
||||
l: 'channels'
|
||||
};
|
||||
let roomName = type === SubscriptionType.DIRECT ? sender.username : name;
|
||||
if (type === SubscriptionType.OMNICHANNEL) {
|
||||
roomName = sender.name;
|
||||
}
|
||||
|
||||
const params = {
|
||||
host,
|
||||
rid,
|
||||
messageId,
|
||||
path: `${types[type]}/${roomName}`
|
||||
};
|
||||
store.dispatch(deepLinkingOpen(params));
|
||||
return;
|
||||
}
|
||||
|
||||
const params = {
|
||||
host,
|
||||
rid,
|
||||
messageId,
|
||||
path: `${types[type]}/${roomName}`
|
||||
};
|
||||
store.dispatch(deepLinkingOpen(params));
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
store.dispatch(appInit());
|
||||
};
|
||||
|
||||
export const getDeviceToken = (): string => deviceToken;
|
||||
|
|
|
@ -105,13 +105,15 @@ const displayVideoConferenceNotification = async (notification: NotificationData
|
|||
const setBackgroundNotificationHandler = () => {
|
||||
createChannel();
|
||||
messaging().setBackgroundMessageHandler(async message => {
|
||||
const notification: NotificationData = ejson.parse(message?.data?.ejson as string);
|
||||
if (notification?.notificationType === VIDEO_CONF_TYPE) {
|
||||
if (notification.status === 0) {
|
||||
await displayVideoConferenceNotification(notification);
|
||||
} else if (notification.status === 4) {
|
||||
const id = `${notification.rid}${notification.caller?._id}`.replace(/[^A-Za-z0-9]/g, '');
|
||||
await notifee.cancelNotification(id);
|
||||
if (message?.data?.ejson) {
|
||||
const notification: NotificationData = ejson.parse(message?.data?.ejson as string);
|
||||
if (notification?.notificationType === VIDEO_CONF_TYPE) {
|
||||
if (notification.status === 0) {
|
||||
await displayVideoConferenceNotification(notification);
|
||||
} else if (notification.status === 4) {
|
||||
const id = `${notification.rid}${notification.caller?._id}`.replace(/[^A-Za-z0-9]/g, '');
|
||||
await notifee.cancelNotification(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -905,6 +905,12 @@ export const removePushToken = (): Promise<boolean | void> => {
|
|||
return Promise.resolve();
|
||||
};
|
||||
|
||||
// RC 6.6.0
|
||||
export const pushTest = () => sdk.post('push.test');
|
||||
|
||||
// RC 6.5.0
|
||||
export const pushInfo = () => sdk.get('push.info');
|
||||
|
||||
export const sendEmailCode = () => {
|
||||
const { username } = reduxStore.getState().login.user as IUser;
|
||||
// RC 3.1.0
|
||||
|
|
|
@ -23,6 +23,7 @@ import permissions from './permissions';
|
|||
import roles from './roles';
|
||||
import videoConf from './videoConf';
|
||||
import usersRoles from './usersRoles';
|
||||
import troubleshootingNotification from './troubleshootingNotification';
|
||||
import supportedVersions from './supportedVersions';
|
||||
import inAppFeedback from './inAppFeedback';
|
||||
|
||||
|
@ -50,6 +51,7 @@ export default combineReducers({
|
|||
roles,
|
||||
videoConf,
|
||||
usersRoles,
|
||||
troubleshootingNotification,
|
||||
supportedVersions,
|
||||
inAppFeedback
|
||||
});
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import { setTroubleshootingNotification, initTroubleshootingNotification } from '../actions/troubleshootingNotification';
|
||||
import { mockedStore } from './mockedStore';
|
||||
import { ITroubleshootingNotification, initialState } from './troubleshootingNotification';
|
||||
|
||||
describe('test troubleshootingNotification reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
const state = mockedStore.getState().troubleshootingNotification;
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should return correctly the value after call initTroubleshootingNotification action', () => {
|
||||
mockedStore.dispatch(initTroubleshootingNotification());
|
||||
const state = mockedStore.getState().troubleshootingNotification;
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should return correctly value after call troubleshootingNotification action', () => {
|
||||
const payload: ITroubleshootingNotification = {
|
||||
deviceNotificationEnabled: true,
|
||||
issuesWithNotifications: false,
|
||||
defaultPushGateway: true,
|
||||
pushGatewayEnabled: true,
|
||||
consumptionPercentage: 0,
|
||||
isCommunityEdition: false
|
||||
};
|
||||
mockedStore.dispatch(setTroubleshootingNotification(payload));
|
||||
const state = mockedStore.getState().troubleshootingNotification;
|
||||
expect(state).toEqual(payload);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
import { TROUBLESHOOTING_NOTIFICATION } from '../actions/actionsTypes';
|
||||
import { TActionTroubleshootingNotification } from '../actions/troubleshootingNotification';
|
||||
|
||||
export interface ITroubleshootingNotification {
|
||||
deviceNotificationEnabled: boolean;
|
||||
pushGatewayEnabled: boolean;
|
||||
defaultPushGateway: boolean;
|
||||
issuesWithNotifications: boolean;
|
||||
consumptionPercentage: number;
|
||||
isCommunityEdition: boolean;
|
||||
}
|
||||
|
||||
export const initialState: ITroubleshootingNotification = {
|
||||
deviceNotificationEnabled: false,
|
||||
pushGatewayEnabled: false,
|
||||
defaultPushGateway: false,
|
||||
issuesWithNotifications: false,
|
||||
consumptionPercentage: 0,
|
||||
isCommunityEdition: false
|
||||
};
|
||||
|
||||
export default (state = initialState, action: TActionTroubleshootingNotification): ITroubleshootingNotification => {
|
||||
switch (action.type) {
|
||||
case TROUBLESHOOTING_NOTIFICATION.SET:
|
||||
return {
|
||||
...state,
|
||||
...action.payload
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
|
@ -14,6 +14,7 @@ import inviteLinks from './inviteLinks';
|
|||
import createDiscussion from './createDiscussion';
|
||||
import encryption from './encryption';
|
||||
import videoConf from './videoConf';
|
||||
import troubleshootingNotification from './troubleshootingNotification';
|
||||
|
||||
const root = function* root() {
|
||||
yield all([
|
||||
|
@ -30,7 +31,8 @@ const root = function* root() {
|
|||
createDiscussion(),
|
||||
inquiry(),
|
||||
encryption(),
|
||||
videoConf()
|
||||
videoConf(),
|
||||
troubleshootingNotification()
|
||||
]);
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import { inviteLinksRequest } from '../actions/inviteLinks';
|
|||
import { showErrorAlert } from '../lib/methods/helpers/info';
|
||||
import { localAuthenticate } from '../lib/methods/helpers/localAuthentication';
|
||||
import { encryptionInit, encryptionStop } from '../actions/encryption';
|
||||
import { initTroubleshootingNotification } from '../actions/troubleshootingNotification';
|
||||
import UserPreferences from '../lib/methods/userPreferences';
|
||||
import { inquiryRequest, inquiryReset } from '../ee/omnichannel/actions/inquiry';
|
||||
import { isOmnichannelStatusAvailable } from '../ee/omnichannel/lib';
|
||||
|
@ -236,6 +237,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
|
|||
yield put(inviteLinksRequest(inviteLinkToken));
|
||||
}
|
||||
yield showSupportedVersionsWarning(server);
|
||||
yield put(initTroubleshootingNotification());
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import { Action } from 'redux';
|
||||
import { call, takeLatest, put } from 'typed-redux-saga';
|
||||
import notifee, { AuthorizationStatus } from '@notifee/react-native';
|
||||
|
||||
import { TROUBLESHOOTING_NOTIFICATION } from '../actions/actionsTypes';
|
||||
import { setTroubleshootingNotification } from '../actions/troubleshootingNotification';
|
||||
import { pushInfo } from '../lib/services/restApi';
|
||||
import log from '../lib/methods/helpers/log';
|
||||
import { appSelector } from '../lib/hooks';
|
||||
import { compareServerVersion } from '../lib/methods/helpers';
|
||||
|
||||
interface IGenericAction extends Action {
|
||||
type: string;
|
||||
}
|
||||
|
||||
function* init() {
|
||||
const serverVersion = yield* appSelector(state => state.server.version);
|
||||
let deviceNotificationEnabled = false;
|
||||
let defaultPushGateway = false;
|
||||
let pushGatewayEnabled = false;
|
||||
try {
|
||||
const { authorizationStatus } = yield* call(notifee.getNotificationSettings);
|
||||
deviceNotificationEnabled = authorizationStatus > AuthorizationStatus.DENIED;
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '6.5.0')) {
|
||||
const pushInfoResult = yield* call(pushInfo);
|
||||
if (pushInfoResult.success) {
|
||||
pushGatewayEnabled = pushInfoResult.pushGatewayEnabled;
|
||||
defaultPushGateway = pushInfoResult.defaultPushGateway;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
||||
const issuesWithNotifications =
|
||||
!deviceNotificationEnabled || (compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '6.6.0') && !pushGatewayEnabled);
|
||||
yield put(
|
||||
setTroubleshootingNotification({
|
||||
deviceNotificationEnabled,
|
||||
defaultPushGateway,
|
||||
pushGatewayEnabled,
|
||||
issuesWithNotifications
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export default function* root(): Generator {
|
||||
yield takeLatest<IGenericAction>(TROUBLESHOOTING_NOTIFICATION.INIT, init);
|
||||
}
|
|
@ -42,6 +42,7 @@ import DisplayPrefsView from '../views/DisplayPrefsView';
|
|||
// Settings Stack
|
||||
import SettingsView from '../views/SettingsView';
|
||||
import SecurityPrivacyView from '../views/SecurityPrivacyView';
|
||||
import PushTroubleshootView from '../views/PushTroubleshootView';
|
||||
import E2EEncryptionSecurityView from '../views/E2EEncryptionSecurityView';
|
||||
import LanguageView from '../views/LanguageView';
|
||||
import ThemeView from '../views/ThemeView';
|
||||
|
@ -118,6 +119,7 @@ const ChatsStackNavigator = () => {
|
|||
<ChatsStack.Screen name='AutoTranslateView' component={AutoTranslateView} />
|
||||
<ChatsStack.Screen name='DirectoryView' component={DirectoryView} options={DirectoryView.navigationOptions} />
|
||||
<ChatsStack.Screen name='NotificationPrefView' component={NotificationPrefView} />
|
||||
<ChatsStack.Screen name='PushTroubleshootView' component={PushTroubleshootView} />
|
||||
<ChatsStack.Screen name='ForwardLivechatView' component={ForwardLivechatView} />
|
||||
<ChatsStack.Screen name='CloseLivechatView' component={CloseLivechatView} />
|
||||
<ChatsStack.Screen name='LivechatEditView' component={LivechatEditView} options={LivechatEditView.navigationOptions} />
|
||||
|
@ -155,6 +157,7 @@ const ProfileStackNavigator = () => {
|
|||
<ProfileStack.Screen name='UserPreferencesView' component={UserPreferencesView} />
|
||||
<ProfileStack.Screen name='ChangeAvatarView' component={ChangeAvatarView} />
|
||||
<ProfileStack.Screen name='UserNotificationPrefView' component={UserNotificationPrefView} />
|
||||
<ProfileStack.Screen name='PushTroubleshootView' component={PushTroubleshootView} />
|
||||
<ProfileStack.Screen name='PickerView' component={PickerView} />
|
||||
</ProfileStack.Navigator>
|
||||
);
|
||||
|
@ -171,6 +174,7 @@ const SettingsStackNavigator = () => {
|
|||
>
|
||||
<SettingsStack.Screen name='SettingsView' component={SettingsView} />
|
||||
<SettingsStack.Screen name='SecurityPrivacyView' component={SecurityPrivacyView} />
|
||||
<SettingsStack.Screen name='PushTroubleshootView' component={PushTroubleshootView} />
|
||||
<SettingsStack.Screen name='E2EEncryptionSecurityView' component={E2EEncryptionSecurityView} />
|
||||
<SettingsStack.Screen name='LanguageView' component={LanguageView} />
|
||||
<SettingsStack.Screen name='ThemeView' component={ThemeView} />
|
||||
|
|
|
@ -27,6 +27,7 @@ import MessagesView from '../../views/MessagesView';
|
|||
import AutoTranslateView from '../../views/AutoTranslateView';
|
||||
import DirectoryView from '../../views/DirectoryView';
|
||||
import NotificationPrefView from '../../views/NotificationPreferencesView';
|
||||
import PushTroubleshootView from '../../views/PushTroubleshootView';
|
||||
import ForwardLivechatView from '../../views/ForwardLivechatView';
|
||||
import ForwardMessageView from '../../views/ForwardMessageView';
|
||||
import CloseLivechatView from '../../views/CloseLivechatView';
|
||||
|
@ -187,6 +188,7 @@ const ModalStackNavigator = React.memo(({ navigation }: INavigation) => {
|
|||
<ModalStack.Screen name='SecurityPrivacyView' component={SecurityPrivacyView} />
|
||||
<ModalStack.Screen name='MediaAutoDownloadView' component={MediaAutoDownloadView} />
|
||||
<ModalStack.Screen name='E2EEncryptionSecurityView' component={E2EEncryptionSecurityView} />
|
||||
<ModalStack.Screen name='PushTroubleshootView' component={PushTroubleshootView} />
|
||||
<ModalStack.Screen name='SupportedVersionsWarning' component={SupportedVersionsWarning} />
|
||||
</ModalStack.Navigator>
|
||||
</ModalContainer>
|
||||
|
|
|
@ -196,6 +196,7 @@ export type ModalStackParamList = {
|
|||
SecurityPrivacyView: undefined;
|
||||
MediaAutoDownloadView: undefined;
|
||||
E2EEncryptionSecurityView: undefined;
|
||||
PushTroubleshootView: undefined;
|
||||
SupportedVersionsWarning: {
|
||||
showCloseButton?: boolean;
|
||||
};
|
||||
|
|
|
@ -122,6 +122,7 @@ export type ChatsStackParamList = {
|
|||
rid: string;
|
||||
room: TSubscriptionModel;
|
||||
};
|
||||
PushTroubleshootView: undefined;
|
||||
CloseLivechatView: {
|
||||
rid: string;
|
||||
departmentId?: string;
|
||||
|
@ -188,6 +189,7 @@ export type ProfileStackParamList = {
|
|||
ProfileView: undefined;
|
||||
UserPreferencesView: undefined;
|
||||
UserNotificationPrefView: undefined;
|
||||
PushTroubleshootView: undefined;
|
||||
ChangeAvatarView: {
|
||||
context: TChangeAvatarViewContext;
|
||||
titleHeader?: string;
|
||||
|
@ -207,6 +209,7 @@ export type SettingsStackParamList = {
|
|||
ProfileView: undefined;
|
||||
DisplayPrefsView: undefined;
|
||||
MediaAutoDownloadView: undefined;
|
||||
PushTroubleshootView: undefined;
|
||||
};
|
||||
|
||||
export type AdminPanelStackParamList = {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { RouteProp, useNavigation, useRoute } from '@react-navigation/core';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Switch, Text } from 'react-native';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
|
||||
import { TActionSheetOptionsItem, useActionSheet } from '../../containers/ActionSheet';
|
||||
import { CustomIcon } from '../../containers/CustomIcon';
|
||||
|
@ -91,8 +92,11 @@ const RenderSwitch = ({ preference, room, onChangeValue }: IBaseParams) => {
|
|||
const NotificationPreferencesView = (): React.ReactElement => {
|
||||
const route = useRoute<RouteProp<ChatsStackParamList, 'NotificationPrefView'>>();
|
||||
const { rid, room } = route.params;
|
||||
const navigation = useNavigation();
|
||||
const serverVersion = useAppSelector(state => state.server.version);
|
||||
const navigation = useNavigation<StackNavigationProp<ChatsStackParamList, 'NotificationPrefView'>>();
|
||||
const { serverVersion, isMasterDetail } = useAppSelector(state => ({
|
||||
serverVersion: state.server.version,
|
||||
isMasterDetail: state.app.isMasterDetail
|
||||
}));
|
||||
const [hideUnreadStatus, setHideUnreadStatus] = useState(room.hideUnreadStatus);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -108,6 +112,14 @@ const NotificationPreferencesView = (): React.ReactElement => {
|
|||
});
|
||||
}, []);
|
||||
|
||||
const navigateToPushTroubleshootView = () => {
|
||||
if (isMasterDetail) {
|
||||
navigation.navigate('ModalStackNavigator', { screen: 'PushTroubleshootView' });
|
||||
} else {
|
||||
navigation.navigate('PushTroubleshootView');
|
||||
}
|
||||
};
|
||||
|
||||
const saveNotificationSettings = async (key: TUnionOptionsRoomNotifications, params: IRoomNotifications, onError: Function) => {
|
||||
try {
|
||||
// @ts-ignore
|
||||
|
@ -202,6 +214,13 @@ const NotificationPreferencesView = (): React.ReactElement => {
|
|||
onChangeValue={saveNotificationSettings}
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
title='Troubleshooting'
|
||||
onPress={navigateToPushTroubleshootView}
|
||||
testID='notification-preference-view-troubleshooting'
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Info info='Push_Notifications_Alert_Info' />
|
||||
</List.Section>
|
||||
<List.Section title='Email'>
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import React from 'react';
|
||||
import { Alert, StyleSheet, Text } from 'react-native';
|
||||
|
||||
import * as List from '../../../containers/List';
|
||||
import i18n from '../../../i18n';
|
||||
import { useAppSelector } from '../../../lib/hooks';
|
||||
import { useTheme } from '../../../theme';
|
||||
import sharedStyles from '../../Styles';
|
||||
|
||||
const WARNING_MINIMUM_VALUE = 70;
|
||||
const WARNING_MAXIMUM_VALUE = 90;
|
||||
|
||||
export default function CommunityEditionPushQuota(): React.ReactElement | null {
|
||||
const { colors } = useTheme();
|
||||
const { consumptionPercentage, isCommunityEdition } = useAppSelector(state => ({
|
||||
isCommunityEdition: state.troubleshootingNotification.isCommunityEdition,
|
||||
consumptionPercentage: state.troubleshootingNotification.consumptionPercentage
|
||||
}));
|
||||
|
||||
if (!isCommunityEdition) return null;
|
||||
|
||||
const percentage = `${Math.floor(consumptionPercentage)}%`;
|
||||
|
||||
let percentageColor = colors.statusFontSuccess;
|
||||
if (consumptionPercentage > WARNING_MINIMUM_VALUE && consumptionPercentage < WARNING_MAXIMUM_VALUE) {
|
||||
percentageColor = colors.statusFontWarning;
|
||||
}
|
||||
if (consumptionPercentage >= WARNING_MAXIMUM_VALUE) {
|
||||
percentageColor = colors.statusFontDanger;
|
||||
}
|
||||
|
||||
const alertWorkspaceConsumption = () => {
|
||||
Alert.alert(i18n.t('Push_consumption_alert_title'), i18n.t('Push_consumption_alert_description'));
|
||||
};
|
||||
|
||||
return (
|
||||
<List.Section title='Community_edition_push_quota'>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
title='Workspace_consumption'
|
||||
testID='push-troubleshoot-view-workspace-consumption'
|
||||
onPress={alertWorkspaceConsumption}
|
||||
right={() => <Text style={[styles.pickerText, { color: percentageColor }]}>{percentage}</Text>}
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Info info='Workspace_consumption_description' />
|
||||
</List.Section>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
pickerText: {
|
||||
...sharedStyles.textRegular,
|
||||
fontSize: 16
|
||||
}
|
||||
});
|
|
@ -0,0 +1,52 @@
|
|||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
import { Header } from '../../../containers/List';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
marginBottom: 16
|
||||
},
|
||||
headerContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center'
|
||||
},
|
||||
statusContainer: {
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: 5,
|
||||
marginRight: 12
|
||||
}
|
||||
});
|
||||
|
||||
interface ICustomListSection {
|
||||
children: (React.ReactElement | null)[] | React.ReactElement | null;
|
||||
title: string;
|
||||
translateTitle?: boolean;
|
||||
statusColor?: string;
|
||||
}
|
||||
|
||||
const CustomHeader = ({
|
||||
title,
|
||||
translateTitle,
|
||||
statusColor
|
||||
}: {
|
||||
title: string;
|
||||
translateTitle?: boolean;
|
||||
statusColor?: string;
|
||||
}) => (
|
||||
<View style={styles.headerContainer}>
|
||||
<Header {...{ title, translateTitle }} />
|
||||
{statusColor ? <View style={[styles.statusContainer, { backgroundColor: statusColor }]} /> : null}
|
||||
</View>
|
||||
);
|
||||
|
||||
const CustomListSection = ({ children, title, translateTitle, statusColor }: ICustomListSection) => (
|
||||
<View style={styles.container}>
|
||||
{title ? <CustomHeader {...{ title, translateTitle, statusColor }} /> : null}
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
|
||||
export default CustomListSection;
|
|
@ -0,0 +1,50 @@
|
|||
import notifee from '@notifee/react-native';
|
||||
import React from 'react';
|
||||
import { Linking } from 'react-native';
|
||||
|
||||
import * as List from '../../../containers/List';
|
||||
import i18n from '../../../i18n';
|
||||
import { useAppSelector } from '../../../lib/hooks';
|
||||
import { isIOS, showErrorAlert } from '../../../lib/methods/helpers';
|
||||
import { useTheme } from '../../../theme';
|
||||
import CustomListSection from './CustomListSection';
|
||||
|
||||
export default function DeviceNotificationSettings(): React.ReactElement {
|
||||
const { colors } = useTheme();
|
||||
const { deviceNotificationEnabled } = useAppSelector(state => ({
|
||||
deviceNotificationEnabled: state.troubleshootingNotification.deviceNotificationEnabled
|
||||
}));
|
||||
|
||||
const goToNotificationSettings = () => {
|
||||
if (isIOS) {
|
||||
Linking.openURL('app-settings:');
|
||||
} else {
|
||||
notifee.openNotificationSettings();
|
||||
}
|
||||
};
|
||||
|
||||
const alertDeviceNotificationSettings = () => {
|
||||
if (deviceNotificationEnabled) return;
|
||||
showErrorAlert(
|
||||
i18n.t('Device_notifications_alert_description'),
|
||||
i18n.t('Device_notifications_alert_title'),
|
||||
goToNotificationSettings
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<CustomListSection
|
||||
title='Device_notification_settings'
|
||||
statusColor={!deviceNotificationEnabled ? colors.userPresenceBusy : colors.userPresenceOnline}
|
||||
>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
title={!deviceNotificationEnabled ? 'Allow_push_notifications_for_rocket_chat' : 'No_further_action_is_needed'}
|
||||
onPress={alertDeviceNotificationSettings}
|
||||
testID='push-troubleshoot-view-allow-push-notifications'
|
||||
disabled={deviceNotificationEnabled}
|
||||
/>
|
||||
<List.Separator />
|
||||
</CustomListSection>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react';
|
||||
import { Linking } from 'react-native';
|
||||
|
||||
import * as List from '../../../containers/List';
|
||||
import { useTheme } from '../../../theme';
|
||||
|
||||
export default function NotificationDelay(): React.ReactElement {
|
||||
const { colors } = useTheme();
|
||||
|
||||
const openNotificationDocumentation = () => Linking.openURL('https://go.rocket.chat/i/push-notifications');
|
||||
|
||||
return (
|
||||
<List.Section title='Notification_delay'>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
title='Documentation'
|
||||
onPress={openNotificationDocumentation}
|
||||
right={() => <List.Icon size={32} name='new-window' color={colors.fontAnnotation} />}
|
||||
testID='push-troubleshoot-view-notification-delay'
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Info info='Notification_delay_description' />
|
||||
</List.Section>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Alert } from 'react-native';
|
||||
|
||||
import * as List from '../../../containers/List';
|
||||
import i18n from '../../../i18n';
|
||||
import { useAppSelector, usePermissions } from '../../../lib/hooks';
|
||||
import { compareServerVersion, showErrorAlertWithEMessage } from '../../../lib/methods/helpers';
|
||||
import { Services } from '../../../lib/services';
|
||||
import { useTheme } from '../../../theme';
|
||||
import CustomListSection from './CustomListSection';
|
||||
|
||||
export default function PushGatewayConnection(): React.ReactElement | null {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { colors } = useTheme();
|
||||
const [testPushNotificationsPermission] = usePermissions(['test-push-notifications']);
|
||||
const { defaultPushGateway, pushGatewayEnabled, serverVersion } = useAppSelector(state => ({
|
||||
pushGatewayEnabled: state.troubleshootingNotification.pushGatewayEnabled,
|
||||
defaultPushGateway: state.troubleshootingNotification.defaultPushGateway,
|
||||
foreground: state.app.foreground,
|
||||
serverVersion: state.server.version
|
||||
}));
|
||||
|
||||
if (!compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '6.6.0')) return null;
|
||||
|
||||
const handleTestPushNotification = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await Services.pushTest();
|
||||
if (result.success) {
|
||||
Alert.alert(i18n.t('Test_push_notification'), i18n.t('Your_push_was_sent_to_s_devices', { s: result.tokensCount }));
|
||||
}
|
||||
} catch (error: any) {
|
||||
showErrorAlertWithEMessage(error, i18n.t('Test_push_notification'));
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
let infoColor = 'Push_gateway_not_connected_description';
|
||||
let statusColor = colors.userPresenceBusy;
|
||||
if (pushGatewayEnabled) {
|
||||
statusColor = colors.userPresenceOnline;
|
||||
infoColor = 'Push_gateway_connected_description';
|
||||
}
|
||||
if (pushGatewayEnabled && !defaultPushGateway) {
|
||||
statusColor = colors.badgeBackgroundLevel3;
|
||||
infoColor = 'Custom_push_gateway_connected_description';
|
||||
}
|
||||
|
||||
return (
|
||||
<CustomListSection
|
||||
title={!defaultPushGateway ? 'Custom_push_gateway_connection' : 'Push_gateway_connection'}
|
||||
statusColor={statusColor}
|
||||
>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
title='Test_push_notification'
|
||||
disabled={!pushGatewayEnabled || !testPushNotificationsPermission || loading}
|
||||
onPress={handleTestPushNotification}
|
||||
testID='push-troubleshoot-view-push-gateway-connection'
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Info info={infoColor} />
|
||||
</CustomListSection>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { initTroubleshootingNotification } from '../../actions/troubleshootingNotification';
|
||||
import * as List from '../../containers/List';
|
||||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
import I18n from '../../i18n';
|
||||
import { SettingsStackParamList } from '../../stacks/types';
|
||||
// import CommunityEditionPushQuota from './components/CommunityEditionPushQuota';
|
||||
import DeviceNotificationSettings from './components/DeviceNotificationSettings';
|
||||
import NotificationDelay from './components/NotificationDelay';
|
||||
import PushGatewayConnection from './components/PushGatewayConnection';
|
||||
|
||||
interface IPushTroubleshootViewProps {
|
||||
navigation: StackNavigationProp<SettingsStackParamList, 'PushTroubleshootView'>;
|
||||
}
|
||||
|
||||
const PushTroubleshootView = ({ navigation }: IPushTroubleshootViewProps): JSX.Element => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
dispatch(initTroubleshootingNotification());
|
||||
}, [])
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
title: I18n.t('Push_Troubleshooting')
|
||||
});
|
||||
}, [navigation]);
|
||||
|
||||
return (
|
||||
<SafeAreaView testID='push-troubleshoot-view'>
|
||||
<StatusBar />
|
||||
<List.Container testID='push-troubleshoot-view-list'>
|
||||
<DeviceNotificationSettings />
|
||||
{/* <CommunityEditionPushQuota /> */}
|
||||
<PushGatewayConnection />
|
||||
<NotificationDelay />
|
||||
</List.Container>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default PushTroubleshootView;
|
|
@ -21,6 +21,7 @@ import { getUserSelector } from '../../selectors/login';
|
|||
import { TNavigation } from '../../stacks/stackType';
|
||||
import { ChatsStackParamList } from '../../stacks/types';
|
||||
import HeaderCallButton from './components/HeaderCallButton';
|
||||
import { TColors, TSupportedThemes, withTheme } from '../../theme';
|
||||
|
||||
interface IRightButtonsProps extends Pick<ISubscription, 't'> {
|
||||
userId?: string;
|
||||
|
@ -43,6 +44,10 @@ interface IRightButtonsProps extends Pick<ISubscription, 't'> {
|
|||
showActionSheet: Function;
|
||||
departmentId?: string;
|
||||
rid?: string;
|
||||
theme?: TSupportedThemes;
|
||||
colors?: TColors;
|
||||
issuesWithNotifications: boolean;
|
||||
notificationsDisabled?: boolean;
|
||||
}
|
||||
|
||||
interface IRigthButtonsState {
|
||||
|
@ -55,6 +60,7 @@ interface IRigthButtonsState {
|
|||
class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsState> {
|
||||
private threadSubscription?: Subscription;
|
||||
private subSubscription?: Subscription;
|
||||
private room?: TSubscriptionModel;
|
||||
|
||||
constructor(props: IRightButtonsProps) {
|
||||
super(props);
|
||||
|
@ -80,8 +86,8 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
if (rid) {
|
||||
try {
|
||||
const subCollection = db.get('subscriptions');
|
||||
const subRecord = await subCollection.find(rid);
|
||||
this.observeSubscription(subRecord);
|
||||
this.room = await subCollection.find(rid);
|
||||
this.observeSubscription(this.room);
|
||||
} catch (e) {
|
||||
console.log("Can't find subscription to observe.");
|
||||
}
|
||||
|
@ -90,7 +96,7 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
|
||||
shouldComponentUpdate(nextProps: IRightButtonsProps, nextState: IRigthButtonsState) {
|
||||
const { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state;
|
||||
const { teamId, status, joined, omnichannelPermissions } = this.props;
|
||||
const { teamId, status, joined, omnichannelPermissions, theme, issuesWithNotifications, notificationsDisabled } = this.props;
|
||||
if (nextProps.teamId !== teamId) {
|
||||
return true;
|
||||
}
|
||||
|
@ -100,9 +106,18 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
if (nextProps.joined !== joined) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.theme !== theme) {
|
||||
return true;
|
||||
}
|
||||
if (nextState.isFollowingThread !== isFollowingThread) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.issuesWithNotifications !== issuesWithNotifications) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.notificationsDisabled !== notificationsDisabled) {
|
||||
return true;
|
||||
}
|
||||
if (!dequal(nextProps.omnichannelPermissions, omnichannelPermissions)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -288,6 +303,31 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
showActionSheet({ options });
|
||||
};
|
||||
|
||||
navigateToNotificationOrPushTroubleshoot = () => {
|
||||
const { room } = this;
|
||||
const { rid, navigation, isMasterDetail, issuesWithNotifications } = this.props;
|
||||
|
||||
if (!rid || !room) {
|
||||
return;
|
||||
}
|
||||
if (!issuesWithNotifications && room) {
|
||||
if (isMasterDetail) {
|
||||
navigation.navigate('ModalStackNavigator', {
|
||||
screen: 'NotificationPrefView',
|
||||
params: { rid, room }
|
||||
});
|
||||
} else {
|
||||
navigation.navigate('NotificationPrefView', { rid, room });
|
||||
}
|
||||
} else if (isMasterDetail) {
|
||||
navigation.navigate('ModalStackNavigator', {
|
||||
screen: 'PushTroubleshootView'
|
||||
});
|
||||
} else {
|
||||
navigation.navigate('PushTroubleshootView');
|
||||
}
|
||||
};
|
||||
|
||||
goSearchView = () => {
|
||||
logEvent(events.ROOM_GO_SEARCH);
|
||||
const { rid, t, navigation, isMasterDetail, encrypted } = this.props;
|
||||
|
@ -321,7 +361,7 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
|
||||
render() {
|
||||
const { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state;
|
||||
const { t, tmid, threadsEnabled, rid } = this.props;
|
||||
const { t, tmid, threadsEnabled, rid, colors, issuesWithNotifications, notificationsDisabled } = this.props;
|
||||
|
||||
if (t === 'l') {
|
||||
if (!this.isOmnichannelPreview()) {
|
||||
|
@ -346,6 +386,14 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
}
|
||||
return (
|
||||
<HeaderButton.Container>
|
||||
{issuesWithNotifications || notificationsDisabled ? (
|
||||
<HeaderButton.Item
|
||||
color={issuesWithNotifications ? colors!.fontDanger : colors!.headerTintColor}
|
||||
iconName='notification-disabled'
|
||||
onPress={this.navigateToNotificationOrPushTroubleshoot}
|
||||
testID='room-view-push-troubleshoot'
|
||||
/>
|
||||
) : null}
|
||||
{rid ? <HeaderCallButton rid={rid} /> : null}
|
||||
{threadsEnabled ? (
|
||||
<HeaderButton.Item
|
||||
|
@ -365,7 +413,8 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
userId: getUserSelector(state).id,
|
||||
threadsEnabled: state.settings.Threads_enabled as boolean,
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
livechatRequestComment: state.settings.Livechat_request_comment_when_closing_conversation as boolean
|
||||
livechatRequestComment: state.settings.Livechat_request_comment_when_closing_conversation as boolean,
|
||||
issuesWithNotifications: state.troubleshootingNotification.issuesWithNotifications
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(RightButtonsContainer);
|
||||
export default connect(mapStateToProps)(withTheme(RightButtonsContainer));
|
||||
|
|
|
@ -456,7 +456,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
const t = room?.t;
|
||||
const teamMain = 'teamMain' in room ? room?.teamMain : false;
|
||||
const omnichannelPermissions = { canForwardGuest, canReturnQueue, canPlaceLivechatOnHold };
|
||||
|
||||
const iSubRoom = room as ISubscription;
|
||||
navigation.setOptions({
|
||||
headerShown: true,
|
||||
headerTitleAlign: 'left',
|
||||
|
@ -513,6 +513,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
toggleFollowThread={this.toggleFollowThread}
|
||||
showActionSheet={this.showActionSheet}
|
||||
departmentId={departmentId}
|
||||
notificationsDisabled={iSubRoom?.disableNotifications}
|
||||
/>
|
||||
)
|
||||
});
|
||||
|
|
|
@ -92,6 +92,7 @@ interface IRoomsListViewProps {
|
|||
createPrivateChannelPermission: [];
|
||||
createDiscussionPermission: [];
|
||||
serverVersion: string;
|
||||
issuesWithNotifications: boolean;
|
||||
}
|
||||
|
||||
interface IRoomsListViewState {
|
||||
|
@ -146,6 +147,7 @@ const shouldUpdateProps = [
|
|||
'createPublicChannelPermission',
|
||||
'createPrivateChannelPermission',
|
||||
'createDiscussionPermission',
|
||||
'issuesWithNotifications',
|
||||
'supportedVersionsStatus'
|
||||
];
|
||||
|
||||
|
@ -200,7 +202,6 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
const { navigation, dispatch } = this.props;
|
||||
this.handleHasPermission();
|
||||
this.mounted = true;
|
||||
|
||||
this.unsubscribeFocus = navigation.addListener('focus', () => {
|
||||
this.animated = true;
|
||||
// Check if there were changes with sort preference, then call getSubscription to remount the list
|
||||
|
@ -334,6 +335,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
createDiscussionPermission,
|
||||
showAvatar,
|
||||
displayMode,
|
||||
issuesWithNotifications,
|
||||
supportedVersionsStatus
|
||||
} = this.props;
|
||||
const { item } = this.state;
|
||||
|
@ -358,6 +360,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
insets.left !== prevProps.insets.left ||
|
||||
insets.right !== prevProps.insets.right ||
|
||||
notificationPresenceCap !== prevProps.notificationPresenceCap ||
|
||||
issuesWithNotifications !== prevProps.issuesWithNotifications ||
|
||||
supportedVersionsStatus !== prevProps.supportedVersionsStatus
|
||||
) {
|
||||
this.setHeader();
|
||||
|
@ -411,7 +414,8 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
|
||||
getHeader = (): StackNavigationOptions => {
|
||||
const { searching, canCreateRoom } = this.state;
|
||||
const { navigation, isMasterDetail, notificationPresenceCap, supportedVersionsStatus, theme } = this.props;
|
||||
const { navigation, isMasterDetail, notificationPresenceCap, issuesWithNotifications, supportedVersionsStatus, theme } =
|
||||
this.props;
|
||||
if (searching) {
|
||||
return {
|
||||
headerTitleAlign: 'left',
|
||||
|
@ -458,6 +462,14 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
headerTitle: () => <RoomsListHeaderView />,
|
||||
headerRight: () => (
|
||||
<HeaderButton.Container>
|
||||
{issuesWithNotifications ? (
|
||||
<HeaderButton.Item
|
||||
iconName='notification-disabled'
|
||||
onPress={this.navigateToPushTroubleshootView}
|
||||
testID='rooms-list-view-push-troubleshoot'
|
||||
color={themes[theme].fontDanger}
|
||||
/>
|
||||
) : null}
|
||||
{canCreateRoom ? (
|
||||
<HeaderButton.Item
|
||||
iconName='create'
|
||||
|
@ -775,6 +787,15 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
}
|
||||
};
|
||||
|
||||
navigateToPushTroubleshootView = () => {
|
||||
const { navigation, isMasterDetail } = this.props;
|
||||
if (isMasterDetail) {
|
||||
navigation.navigate('ModalStackNavigator', { screen: 'PushTroubleshootView' });
|
||||
} else {
|
||||
navigation.navigate('PushTroubleshootView');
|
||||
}
|
||||
};
|
||||
|
||||
goQueue = () => {
|
||||
logEvent(events.RL_GO_QUEUE);
|
||||
const { navigation, isMasterDetail, inquiryEnabled } = this.props;
|
||||
|
@ -1008,7 +1029,8 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
createPublicChannelPermission: state.permissions['create-c'],
|
||||
createPrivateChannelPermission: state.permissions['create-p'],
|
||||
createDiscussionPermission: state.permissions['start-discussion'],
|
||||
serverVersion: state.server.version
|
||||
serverVersion: state.server.version,
|
||||
issuesWithNotifications: state.troubleshootingNotification.issuesWithNotifications
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withDimensions(withTheme(withSafeAreaInsets(RoomsListView))));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useEffect, useLayoutEffect, useState } from 'react';
|
||||
import { Switch } from 'react-native';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { CompositeNavigationProp, useNavigation } from '@react-navigation/native';
|
||||
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
import * as List from '../../containers/List';
|
||||
|
@ -15,16 +15,25 @@ import { Services } from '../../lib/services';
|
|||
import { useAppSelector } from '../../lib/hooks';
|
||||
import ListPicker from './ListPicker';
|
||||
import log from '../../lib/methods/helpers/log';
|
||||
import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types';
|
||||
import { useUserPreferences } from '../../lib/methods';
|
||||
import { NOTIFICATION_IN_APP_VIBRATION, SWITCH_TRACK_COLOR } from '../../lib/constants';
|
||||
|
||||
type TNavigation = CompositeNavigationProp<
|
||||
StackNavigationProp<ProfileStackParamList, 'UserNotificationPrefView'>,
|
||||
StackNavigationProp<MasterDetailInsideStackParamList>
|
||||
>;
|
||||
|
||||
const UserNotificationPreferencesView = () => {
|
||||
const [inAppVibration, setInAppVibration] = useUserPreferences<boolean>(NOTIFICATION_IN_APP_VIBRATION, true);
|
||||
const [preferences, setPreferences] = useState({} as INotificationPreferences);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const navigation = useNavigation<StackNavigationProp<ProfileStackParamList, 'UserNotificationPrefView'>>();
|
||||
const userId = useAppSelector(state => getUserSelector(state).id);
|
||||
const navigation = useNavigation<TNavigation>();
|
||||
const { userId, isMasterDetail } = useAppSelector(state => ({
|
||||
userId: getUserSelector(state).id,
|
||||
isMasterDetail: state.app.isMasterDetail
|
||||
}));
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
|
@ -62,6 +71,14 @@ const UserNotificationPreferencesView = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const navigateToPushTroubleshootView = () => {
|
||||
if (isMasterDetail) {
|
||||
navigation.navigate('ModalStackNavigator', { screen: 'PushTroubleshootView' });
|
||||
} else {
|
||||
navigation.navigate('PushTroubleshootView');
|
||||
}
|
||||
};
|
||||
|
||||
const toggleInAppVibration = () => {
|
||||
setInAppVibration(!inAppVibration);
|
||||
};
|
||||
|
@ -97,6 +114,13 @@ const UserNotificationPreferencesView = () => {
|
|||
value={preferences.pushNotifications}
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
title='Troubleshooting'
|
||||
onPress={navigateToPushTroubleshootView}
|
||||
testID='user-notification-preference-view-troubleshooting'
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Info info='Push_Notifications_Alert_Info' />
|
||||
</List.Section>
|
||||
|
||||
|
|
|
@ -534,6 +534,11 @@ PODS:
|
|||
- React-Core
|
||||
- RNMathView (1.0.0):
|
||||
- iosMath
|
||||
- RNNotifee (7.8.0):
|
||||
- React-Core
|
||||
- RNNotifee/NotifeeCore (= 7.8.0)
|
||||
- RNNotifee/NotifeeCore (7.8.0):
|
||||
- React-Core
|
||||
- RNReanimated (2.8.0):
|
||||
- DoubleConversion
|
||||
- FBLazyVector
|
||||
|
@ -666,6 +671,7 @@ DEPENDENCIES:
|
|||
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
|
||||
- RNLocalize (from `../node_modules/react-native-localize`)
|
||||
- RNMathView (from `../node_modules/react-native-math-view/ios`)
|
||||
- "RNNotifee (from `../node_modules/@notifee/react-native`)"
|
||||
- RNReanimated (from `../node_modules/react-native-reanimated`)
|
||||
- RNRootView (from `../node_modules/rn-root-view`)
|
||||
- RNScreens (from `../node_modules/react-native-screens`)
|
||||
|
@ -857,6 +863,8 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/react-native-localize"
|
||||
RNMathView:
|
||||
:path: "../node_modules/react-native-math-view/ios"
|
||||
RNNotifee:
|
||||
:path: "../node_modules/@notifee/react-native"
|
||||
RNReanimated:
|
||||
:path: "../node_modules/react-native-reanimated"
|
||||
RNRootView:
|
||||
|
@ -972,6 +980,7 @@ SPEC CHECKSUMS:
|
|||
RNImageCropPicker: 97289cd94fb01ab79db4e5c92938be4d0d63415d
|
||||
RNLocalize: 82a569022724d35461e2dc5b5d015a13c3ca995b
|
||||
RNMathView: 4c8a3c081fa671ab3136c51fa0bdca7ffb708bd5
|
||||
RNNotifee: f3c01b391dd8e98e67f539f9a35a9cbcd3bae744
|
||||
RNReanimated: 64573e25e078ae6bec03b891586d50b9ec284393
|
||||
RNRootView: 895a4813dedeaca82db2fa868ca1c333d790e494
|
||||
RNScreens: fa9b582d85ae5d62c91c66003b5278458fed7aaa
|
||||
|
|
|
@ -19,11 +19,6 @@ module.exports = {
|
|||
platforms: {
|
||||
ios: null
|
||||
}
|
||||
},
|
||||
'@notifee/react-native': {
|
||||
platforms: {
|
||||
ios: null
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue