[IMPROVE] Visibility of the “incoming chats” in queue (#4039)
* [IMPROVE] Visibility of the “incoming chats” in queue * fix the custom icon for rtl * fix thumb colors * clean queue empty * added alert to confirm enable omnichannel * switch to normal * fix storyshot because was added a new props to list item * fix height container * minor tweak * minor tweak * fix title
This commit is contained in:
parent
064920e61b
commit
0a67cb8096
|
@ -11,6 +11,7 @@ interface IListIcon {
|
|||
color?: string | null;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
testID?: string;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
@ -20,12 +21,12 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const ListIcon = React.memo(({ name, color, style, testID }: IListIcon) => {
|
||||
const ListIcon = React.memo(({ name, color, style, testID, size }: IListIcon) => {
|
||||
const { theme } = useTheme();
|
||||
|
||||
return (
|
||||
<View style={[styles.icon, style]}>
|
||||
<CustomIcon name={name} color={color ?? themes[theme].auxiliaryText} size={ICON_SIZE} testID={testID} />
|
||||
<CustomIcon name={name} color={color ?? themes[theme].auxiliaryText} size={size ?? ICON_SIZE} testID={testID} />
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { I18nManager, StyleSheet, Text, View } from 'react-native';
|
||||
import { I18nManager, StyleProp, StyleSheet, Text, TextStyle, View } from 'react-native';
|
||||
|
||||
import Touch from '../../utils/touch';
|
||||
import { themes } from '../../lib/constants';
|
||||
|
@ -66,6 +66,8 @@ interface IListItemContent {
|
|||
translateSubtitle?: boolean;
|
||||
showActionIndicator?: boolean;
|
||||
alert?: boolean;
|
||||
heightContainer?: number;
|
||||
styleTitle?: StyleProp<TextStyle>;
|
||||
}
|
||||
|
||||
const Content = React.memo(
|
||||
|
@ -81,16 +83,20 @@ const Content = React.memo(
|
|||
translateTitle = true,
|
||||
translateSubtitle = true,
|
||||
showActionIndicator = false,
|
||||
theme
|
||||
theme,
|
||||
heightContainer,
|
||||
styleTitle
|
||||
}: IListItemContent) => {
|
||||
const { fontScale } = useDimensions();
|
||||
|
||||
return (
|
||||
<View style={[styles.container, disabled && styles.disabled, { height: BASE_HEIGHT * fontScale }]} testID={testID}>
|
||||
<View
|
||||
style={[styles.container, disabled && styles.disabled, { height: (heightContainer || BASE_HEIGHT) * fontScale }]}
|
||||
testID={testID}>
|
||||
{left ? <View style={styles.leftContainer}>{left()}</View> : null}
|
||||
<View style={styles.textContainer}>
|
||||
<View style={styles.textAlertContainer}>
|
||||
<Text style={[styles.title, { color: color || themes[theme].titleText }]} numberOfLines={1}>
|
||||
<Text style={[styles.title, styleTitle, { color: color || themes[theme].titleText }]} numberOfLines={1}>
|
||||
{translateTitle && title ? I18n.t(title) : title}
|
||||
</Text>
|
||||
{alert ? (
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { StyleSheet, Text, View, ViewStyle } from 'react-native';
|
||||
import { StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native';
|
||||
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import { getUnreadStyle } from './getUnreadStyle';
|
||||
|
@ -33,7 +33,7 @@ export interface IUnreadBadge {
|
|||
unread?: number;
|
||||
userMentions?: number;
|
||||
groupMentions?: number;
|
||||
style?: ViewStyle;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
tunread?: [];
|
||||
tunreadUser?: [];
|
||||
tunreadGroup?: [];
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import React from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
|
||||
import { useTheme } from '../../../../theme';
|
||||
import { themes } from '../../../../lib/constants';
|
||||
import { CustomIcon } from '../../../../lib/Icons';
|
||||
import * as List from '../../../../containers/List';
|
||||
import styles from './styles';
|
||||
import UnreadBadge from '../../../../containers/UnreadBadge';
|
||||
import i18n from '../../../../i18n';
|
||||
|
||||
interface IOmnichannelQueue {
|
||||
queueSize?: number;
|
||||
onPress(): void;
|
||||
}
|
||||
|
||||
const OmnichannelQueue = ({ queueSize, onPress }: IOmnichannelQueue) => {
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<>
|
||||
<List.Item
|
||||
title='Omnichannel_queue'
|
||||
heightContainer={50}
|
||||
left={() => <List.Icon name='queue' size={24} color={themes[theme].auxiliaryTintColor} />}
|
||||
color={themes[theme].bodyText}
|
||||
onPress={queueSize ? onPress : undefined}
|
||||
styleTitle={styles.titleOmnichannelQueue}
|
||||
right={() => (
|
||||
<View style={styles.omnichannelRightContainer}>
|
||||
{queueSize ? (
|
||||
<>
|
||||
<UnreadBadge style={[styles.queueIcon, { backgroundColor: themes[theme].tintColor }]} unread={queueSize} />
|
||||
<CustomIcon name='chevron-right' style={styles.actionIndicator} color={themes[theme].bodyText} size={24} />
|
||||
</>
|
||||
) : (
|
||||
<Text style={[styles.emptyText, { color: themes[theme].auxiliaryTintColor }]}>{i18n.t('Empty')}</Text>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default OmnichannelQueue;
|
|
@ -0,0 +1,77 @@
|
|||
import React, { memo, useEffect, useState } from 'react';
|
||||
import { Switch, View } from 'react-native';
|
||||
|
||||
import * as List from '../../../../containers/List';
|
||||
import styles from './styles';
|
||||
import { SWITCH_TRACK_COLOR, themes } from '../../../../lib/constants';
|
||||
import { useTheme } from '../../../../theme';
|
||||
import RocketChat from '../../../../lib/rocketchat';
|
||||
import { IUser } from '../../../../definitions/IUser';
|
||||
import { showConfirmationAlert } from '../../../../utils/info';
|
||||
import I18n from '../../../../i18n';
|
||||
import { changeLivechatStatus, isOmnichannelStatusAvailable } from '../../lib';
|
||||
import OmnichannelQueue from './OmnichannelQueue';
|
||||
|
||||
interface IOmnichannelStatus {
|
||||
searching: boolean;
|
||||
goQueue: () => void;
|
||||
queueSize: number;
|
||||
inquiryEnabled: boolean;
|
||||
user: IUser;
|
||||
}
|
||||
|
||||
const OmnichannelStatus = memo(({ searching, goQueue, queueSize, user }: IOmnichannelStatus) => {
|
||||
const { theme } = useTheme();
|
||||
const [status, setStatus] = useState(isOmnichannelStatusAvailable(user));
|
||||
|
||||
useEffect(() => {
|
||||
setStatus(isOmnichannelStatusAvailable(user));
|
||||
}, [user.statusLivechat]);
|
||||
|
||||
if (searching || !(RocketChat.isOmnichannelModuleAvailable() && user?.roles?.includes('livechat-agent'))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const toggleLivechat = async () => {
|
||||
// if not-available, prompt to change to available
|
||||
if (!isOmnichannelStatusAvailable(user)) {
|
||||
showConfirmationAlert({
|
||||
message: I18n.t('Omnichannel_enable_alert'),
|
||||
confirmationText: I18n.t('Yes'),
|
||||
onPress: async () => {
|
||||
try {
|
||||
await changeLivechatStatus();
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
try {
|
||||
setStatus(v => !v);
|
||||
await changeLivechatStatus();
|
||||
} catch {
|
||||
setStatus(v => !v);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<List.Item
|
||||
title='Omnichannel'
|
||||
color={themes[theme].bodyText}
|
||||
onPress={toggleLivechat}
|
||||
right={() => (
|
||||
<View style={styles.omnichannelRightContainer}>
|
||||
<Switch value={status} trackColor={SWITCH_TRACK_COLOR} onValueChange={toggleLivechat} />
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
<List.Separator />
|
||||
{status ? <OmnichannelQueue queueSize={queueSize} onPress={goQueue} /> : null}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default OmnichannelStatus;
|
|
@ -0,0 +1,23 @@
|
|||
import { I18nManager, StyleSheet } from 'react-native';
|
||||
|
||||
import sharedStyles from '../../../../views/Styles';
|
||||
|
||||
export default StyleSheet.create({
|
||||
queueIcon: {
|
||||
marginHorizontal: 10
|
||||
},
|
||||
omnichannelRightContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
titleOmnichannelQueue: {
|
||||
...sharedStyles.textMedium
|
||||
},
|
||||
emptyText: {
|
||||
...sharedStyles.textRegular,
|
||||
fontSize: 12
|
||||
},
|
||||
actionIndicator: {
|
||||
...(I18nManager.isRTL ? { transform: [{ rotate: '180deg' }] } : {})
|
||||
}
|
||||
});
|
|
@ -1,67 +0,0 @@
|
|||
import React, { memo, useEffect, useState } from 'react';
|
||||
import { Switch, View } from 'react-native';
|
||||
|
||||
import * as List from '../../../containers/List';
|
||||
import styles from '../../../views/RoomsListView/styles';
|
||||
import { SWITCH_TRACK_COLOR, themes } from '../../../lib/constants';
|
||||
import { useTheme } from '../../../theme';
|
||||
import UnreadBadge from '../../../containers/UnreadBadge';
|
||||
import RocketChat from '../../../lib/rocketchat';
|
||||
import { changeLivechatStatus, isOmnichannelStatusAvailable } from '../lib';
|
||||
import { IUser } from '../../../definitions/IUser';
|
||||
import Touch from '../../../utils/touch';
|
||||
|
||||
interface IOmnichannelStatus {
|
||||
searching: boolean;
|
||||
goQueue: () => void;
|
||||
queueSize: number;
|
||||
inquiryEnabled: boolean;
|
||||
user: IUser;
|
||||
}
|
||||
|
||||
const OmnichannelStatus = memo(({ searching, goQueue, queueSize, inquiryEnabled, user }: IOmnichannelStatus) => {
|
||||
const { theme } = useTheme();
|
||||
const [status, setStatus] = useState<boolean>(false);
|
||||
const canUseOmnichannel = RocketChat.isOmnichannelModuleAvailable() && user?.roles?.includes('livechat-agent');
|
||||
|
||||
useEffect(() => {
|
||||
if (canUseOmnichannel) {
|
||||
setStatus(isOmnichannelStatusAvailable(user));
|
||||
}
|
||||
}, [user.statusLivechat]);
|
||||
|
||||
if (searching || !canUseOmnichannel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const toggleLivechat = async () => {
|
||||
try {
|
||||
setStatus(v => !v);
|
||||
await changeLivechatStatus();
|
||||
} catch {
|
||||
setStatus(v => !v);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<List.Item
|
||||
title='Omnichannel'
|
||||
left={() => <List.Icon name='omnichannel' />}
|
||||
color={themes[theme].auxiliaryText}
|
||||
onPress={goQueue}
|
||||
right={() => (
|
||||
<View style={styles.omnichannelRightContainer}>
|
||||
{inquiryEnabled ? <UnreadBadge style={styles.queueIcon} unread={queueSize} /> : null}
|
||||
<Touch theme={theme} onPress={toggleLivechat}>
|
||||
<Switch value={status} trackColor={SWITCH_TRACK_COLOR} onValueChange={toggleLivechat} />
|
||||
</Touch>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default OmnichannelStatus;
|
|
@ -650,7 +650,6 @@
|
|||
"After_seconds_set_by_admin": "بعد {{seconds}} ثوان (حددها المدير)",
|
||||
"Dont_activate": "لا تقم بالتفعيل الآن",
|
||||
"Queued_chats": "محادثات في قائمى الانتظار",
|
||||
"Queue_is_empty": "قائمة الانتظار فارغة",
|
||||
"Logout_from_other_logged_in_locations": "تسجيل الخروج من الأماكن الأخرى",
|
||||
"You_will_be_logged_out_from_other_locations": "سيتم تسجيل خروج من الأماكن الأخرى",
|
||||
"Logged_out_of_other_clients_successfully": "تم تسجيل الخروج من الأماكن الأخرى بنجاح",
|
||||
|
|
|
@ -656,7 +656,6 @@
|
|||
"After_seconds_set_by_admin": "Nach {{seconds}} Sekunden (durch den Admin gesetzt)",
|
||||
"Dont_activate": "Jetzt nicht aktivieren",
|
||||
"Queued_chats": "Chats in der Warteschlange",
|
||||
"Queue_is_empty": "Warteschlange leer",
|
||||
"Logout_from_other_logged_in_locations": "Auf anderen angemeldeten Geräte abmelden",
|
||||
"You_will_be_logged_out_from_other_locations": "Sie werden auf anderen Geräten abgemeldet.",
|
||||
"Logged_out_of_other_clients_successfully": "Erfolgreich von anderen Geräten abgemeldet.",
|
||||
|
|
|
@ -657,7 +657,6 @@
|
|||
"After_seconds_set_by_admin": "After {{seconds}} seconds (set by admin)",
|
||||
"Dont_activate": "Don't activate now",
|
||||
"Queued_chats": "Queued chats",
|
||||
"Queue_is_empty": "Queue is empty",
|
||||
"Logout_from_other_logged_in_locations": "Logout from other logged in locations",
|
||||
"You_will_be_logged_out_from_other_locations": "You'll be logged out from other locations.",
|
||||
"Logged_out_of_other_clients_successfully": "Logged out of other clients successfully",
|
||||
|
@ -808,5 +807,7 @@
|
|||
"Removed__roomName__from_this_team": "removed #{{roomName}} from this Team",
|
||||
"Removed__username__from_team": "removed @{{user_removed}} from this Team",
|
||||
"User_joined_team": "joined this Team",
|
||||
"User_left_team": "left this Team"
|
||||
"User_left_team": "left this Team",
|
||||
"Omnichannel_queue": "Omnichannel queue",
|
||||
"Empty": "Empty"
|
||||
}
|
|
@ -656,7 +656,6 @@
|
|||
"After_seconds_set_by_admin": "Après {{seconds}} secondes (défini par l'administrateur)",
|
||||
"Dont_activate": "Ne pas activer maintenant",
|
||||
"Queued_chats": "Discussions en file d'attente",
|
||||
"Queue_is_empty": "La file d'attente est vide",
|
||||
"Logout_from_other_logged_in_locations": "Déconnexion des autres emplacements connectés",
|
||||
"You_will_be_logged_out_from_other_locations": "Vous serez déconnecté des autres emplacements.",
|
||||
"Logged_out_of_other_clients_successfully": "Déconnexion réussie des autres clients",
|
||||
|
|
|
@ -644,7 +644,6 @@
|
|||
"After_seconds_set_by_admin": "Dopo {{seconds}} secondi (impostati dall'admin)",
|
||||
"Dont_activate": "Non attivare ora",
|
||||
"Queued_chats": "Chat in coda",
|
||||
"Queue_is_empty": "La coda è vuota",
|
||||
"Logout_from_other_logged_in_locations": "Disconnetti da altre postazioni",
|
||||
"You_will_be_logged_out_from_other_locations": "Verrai disconnesso dalle altre postazioni.",
|
||||
"Logged_out_of_other_clients_successfully": "Disconnesso dalle altre postazioni con successo",
|
||||
|
|
|
@ -656,7 +656,6 @@
|
|||
"After_seconds_set_by_admin": "Na {{seconds}} seconden (ingesteld door beheerder)",
|
||||
"Dont_activate": "Nu niet activeren",
|
||||
"Queued_chats": "Chats in de wachtrij",
|
||||
"Queue_is_empty": "Wachtrij is leeg",
|
||||
"Logout_from_other_logged_in_locations": "Afmelden bij andere ingelogde locaties",
|
||||
"You_will_be_logged_out_from_other_locations": "Je wordt uitgelogd van andere locaties.",
|
||||
"Logged_out_of_other_clients_successfully": "Succesvol uitgelogd bij andere klanten",
|
||||
|
|
|
@ -615,7 +615,6 @@
|
|||
"After_seconds_set_by_admin": "Após {{seconds}} segundos (Configurado pelo adm)",
|
||||
"Dont_activate": "Não ativar agora",
|
||||
"Queued_chats": "Bate-papos na fila",
|
||||
"Queue_is_empty": "A fila está vazia",
|
||||
"Logout_from_other_logged_in_locations": "Sair de outros locais logados",
|
||||
"You_will_be_logged_out_from_other_locations": "Você perderá a sessão de outros clientes",
|
||||
"Logged_out_of_other_clients_successfully": "Desconectado de outros clientes com sucesso",
|
||||
|
|
|
@ -656,7 +656,6 @@
|
|||
"After_seconds_set_by_admin": "Через {{seconds}} секунд (установлено администратором сервера)",
|
||||
"Dont_activate": "Не активировать сейчас",
|
||||
"Queued_chats": "Чаты в очереди",
|
||||
"Queue_is_empty": "Очередь пуста",
|
||||
"Logout_from_other_logged_in_locations": "Выйти из всех других подключенных расположений",
|
||||
"You_will_be_logged_out_from_other_locations": "Будет произведен ваш выход из всех других подключенных расположений.",
|
||||
"Logged_out_of_other_clients_successfully": "Выход из других клиентских подключений выполнен успешно",
|
||||
|
|
|
@ -644,7 +644,6 @@
|
|||
"After_seconds_set_by_admin": "{{seconds}} saniye sonra (yönetici tarafından belirlenir)",
|
||||
"Dont_activate": "Şimdi etkinleştirme",
|
||||
"Queued_chats": "Sıralı sohbetler",
|
||||
"Queue_is_empty": "Sıra boş",
|
||||
"Logout_from_other_logged_in_locations": "Giriş yapılan diğer konumlardan çıkış yap",
|
||||
"You_will_be_logged_out_from_other_locations": "Diğer konumlardan çıkış yapacaksınız.",
|
||||
"Logged_out_of_other_clients_successfully": "Diğer istemcilerden başarıyla çıkış yapıldı",
|
||||
|
|
|
@ -642,7 +642,6 @@
|
|||
"After_seconds_set_by_admin": "{{seconds}} 秒 (管理员设定)",
|
||||
"Dont_activate": "現在不要激活",
|
||||
"Queued_chats": "聊天队列",
|
||||
"Queue_is_empty": "队列是空的",
|
||||
"Logout_from_other_logged_in_locations": "注销其他已登陆的设备",
|
||||
"You_will_be_logged_out_from_other_locations": "您将于其他设备上注销",
|
||||
"Logged_out_of_other_clients_successfully": "成功登出其他用户端",
|
||||
|
|
|
@ -644,7 +644,6 @@
|
|||
"After_seconds_set_by_admin": "{{seconds}} 秒 (管理員設定)",
|
||||
"Dont_activate": "現在不要啟用",
|
||||
"Queued_chats": "聊天佇列",
|
||||
"Queue_is_empty": "佇列是空的",
|
||||
"Logout_from_other_logged_in_locations": "登出其他已登入的設備",
|
||||
"You_will_be_logged_out_from_other_locations": "您將於其他設備上登出",
|
||||
"Logged_out_of_other_clients_successfully": "成功登出其他用戶端",
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
|
||||
import { useTheme } from '../../../theme';
|
||||
import * as List from '../../../containers/List';
|
||||
import OmnichannelStatus from '../../../ee/omnichannel/containers/OmnichannelStatus';
|
||||
import OmnichannelStatus from '../../../ee/omnichannel/containers/OmnichannelHeader';
|
||||
import { IUser } from '../../../definitions';
|
||||
import { E2E_BANNER_TYPE, themes } from '../../../lib/constants';
|
||||
|
||||
|
|
|
@ -40,9 +40,7 @@ import { goRoom } from '../../utils/goRoom';
|
|||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import Header, { getHeaderTitlePosition } from '../../containers/Header';
|
||||
import { withDimensions } from '../../dimensions';
|
||||
import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
|
||||
import { getInquiryQueueSelector } from '../../ee/omnichannel/selectors/inquiry';
|
||||
import { changeLivechatStatus, isOmnichannelStatusAvailable } from '../../ee/omnichannel/lib';
|
||||
import { IApplicationState, IBaseScreen, ISubscription, IUser, RootEnum, TSubscriptionModel } from '../../definitions';
|
||||
import styles from './styles';
|
||||
import ServerDropdown from './ServerDropdown';
|
||||
|
@ -745,30 +743,12 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
|
||||
goQueue = () => {
|
||||
logEvent(events.RL_GO_QUEUE);
|
||||
const { navigation, isMasterDetail, queueSize, inquiryEnabled, user } = this.props;
|
||||
|
||||
// if not-available, prompt to change to available
|
||||
if (!isOmnichannelStatusAvailable(user)) {
|
||||
showConfirmationAlert({
|
||||
message: I18n.t('Omnichannel_enable_alert'),
|
||||
confirmationText: I18n.t('Yes'),
|
||||
onPress: async () => {
|
||||
try {
|
||||
await changeLivechatStatus();
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
const { navigation, isMasterDetail, inquiryEnabled } = this.props;
|
||||
|
||||
if (!inquiryEnabled) {
|
||||
return;
|
||||
}
|
||||
// prevent navigation to empty list
|
||||
if (!queueSize) {
|
||||
return showErrorAlert(I18n.t('Queue_is_empty'), I18n.t('Oops'));
|
||||
}
|
||||
|
||||
if (isMasterDetail) {
|
||||
navigation.navigate('ModalStackNavigator', { screen: 'QueueListView' });
|
||||
} else {
|
||||
|
|
|
@ -24,13 +24,6 @@ export default StyleSheet.create({
|
|||
backdrop: {
|
||||
...StyleSheet.absoluteFillObject
|
||||
},
|
||||
queueIcon: {
|
||||
marginHorizontal: 12
|
||||
},
|
||||
omnichannelRightContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
groupTitleContainer: {
|
||||
paddingHorizontal: 12,
|
||||
paddingTop: 17,
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue