[IMPROVE] Support for tag request close when is obligatory to close Omnichannel's Channel (#4353)
* [IMPROVE] Support for tag request close * clean up * refactor isObrigatory and value * fix obligatory * removed onSubmitEditing * create closelivechatview * Refactor Close Omnichannel from ActionSheet to a new Screen * Fix navigation * fix screen title * back to before actionsheetwithinput * added string in pt-br * refactor canSubmit * fix the method closeRoom * comment of server's version * some tweaks * Update app/lib/services/restApi.ts Co-authored-by: Gleidson Daniel Silva <gleidson10daniel@hotmail.com>
This commit is contained in:
parent
08c368c41e
commit
fe7722ca10
|
@ -1,24 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
import ActionSheetContentWithInputAndSubmit from '../../../../containers/ActionSheet/ActionSheetContentWithInputAndSubmit';
|
||||
import I18n from '../../../../i18n';
|
||||
|
||||
const CloseLivechatSheet = ({
|
||||
onSubmit = () => {},
|
||||
onCancel = () => {}
|
||||
}: {
|
||||
onSubmit: (comment: string) => void;
|
||||
onCancel: () => void;
|
||||
}) => (
|
||||
<ActionSheetContentWithInputAndSubmit
|
||||
title={I18n.t('Closing_chat')}
|
||||
description={I18n.t('Please_add_a_comment')}
|
||||
onCancel={onCancel}
|
||||
onSubmit={onSubmit}
|
||||
testID='room-actions-view-close-livechat'
|
||||
placeholder=''
|
||||
secureTextEntry={false}
|
||||
/>
|
||||
);
|
||||
|
||||
export default CloseLivechatSheet;
|
|
@ -840,5 +840,7 @@
|
|||
"Show_badge_for_mentions": "Show badge for mentions",
|
||||
"Show_badge_for_mentions_Info": "Display badge for direct mentions only",
|
||||
"error-init-video-conf": "Error starting video call",
|
||||
"totp-invalid": "Code or password invalid"
|
||||
"totp-invalid": "Code or password invalid",
|
||||
"Close_Chat": "Close Chat",
|
||||
"Select_tags": "Select tags"
|
||||
}
|
|
@ -793,5 +793,7 @@
|
|||
"Mark_as_unread_Info": "Mostrar sala como não lida quando houver mensagens não lidas",
|
||||
"Show_badge_for_mentions": "Mostrar contador para menções",
|
||||
"Show_badge_for_mentions_Info": "Mostrar contador somente para menções diretas",
|
||||
"totp-invalid": "Código ou senha inválida"
|
||||
"totp-invalid": "Código ou senha inválida",
|
||||
"Close_Chat": "Fechar Conversa",
|
||||
"Select_tags": "Selecionar tag(s)"
|
||||
}
|
|
@ -7,14 +7,16 @@ import log from './log';
|
|||
export const closeLivechat = async ({
|
||||
rid,
|
||||
comment,
|
||||
isMasterDetail
|
||||
isMasterDetail,
|
||||
tags
|
||||
}: {
|
||||
rid: string;
|
||||
isMasterDetail: boolean;
|
||||
comment?: string;
|
||||
tags?: string[];
|
||||
}) => {
|
||||
try {
|
||||
await Services.closeLivechat(rid, comment);
|
||||
await Services.closeLivechat(rid, comment, tags);
|
||||
if (isMasterDetail) {
|
||||
Navigation.navigate('DrawerNavigator');
|
||||
} else {
|
||||
|
|
|
@ -18,6 +18,7 @@ import { getDeviceToken } from '../notifications';
|
|||
import { RoomTypes, roomTypeToApiType, unsubscribeRooms } from '../methods';
|
||||
import sdk from './sdk';
|
||||
import { compareServerVersion, getBundleId, isIOS } from '../methods/helpers';
|
||||
import { ILivechatTag } from '../../definitions/ILivechatTag';
|
||||
|
||||
export const createChannel = ({
|
||||
name,
|
||||
|
@ -347,9 +348,15 @@ export const getTeamListRoom = ({
|
|||
return sdk.get('teams.listRooms', params);
|
||||
};
|
||||
|
||||
export const closeLivechat = (rid: string, comment?: string) =>
|
||||
export const closeLivechat = (rid: string, comment?: string, tags?: string[]) => {
|
||||
// RC 3.2.0
|
||||
let params;
|
||||
if (tags && tags?.length) {
|
||||
params = { tags };
|
||||
}
|
||||
// RC 0.29.0
|
||||
sdk.methodCallWrapper('livechat:closeRoom', rid, comment, { clientAction: true });
|
||||
return sdk.methodCallWrapper('livechat:closeRoom', rid, comment, { clientAction: true, ...params });
|
||||
};
|
||||
|
||||
export const editLivechat = (userData: TParams, roomData: TParams): Promise<{ error?: string }> =>
|
||||
// RC 0.55.0
|
||||
|
@ -398,13 +405,7 @@ export const getRoutingConfig = (): Promise<{
|
|||
// RC 2.0.0
|
||||
sdk.methodCallWrapper('livechat:getRoutingConfig');
|
||||
|
||||
export const getTagsList = (): Promise<
|
||||
{
|
||||
_id: string;
|
||||
name: string;
|
||||
departments: string[];
|
||||
}[]
|
||||
> =>
|
||||
export const getTagsList = (): Promise<ILivechatTag[]> =>
|
||||
// RC 2.0.0
|
||||
sdk.methodCallWrapper('livechat:getTagsList');
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import AutoTranslateView from '../views/AutoTranslateView';
|
|||
import DirectoryView from '../views/DirectoryView';
|
||||
import NotificationPrefView from '../views/NotificationPreferencesView';
|
||||
import ForwardLivechatView from '../views/ForwardLivechatView';
|
||||
import CloseLivechatView from '../views/CloseLivechatView';
|
||||
import LivechatEditView from '../views/LivechatEditView';
|
||||
import PickerView from '../views/PickerView';
|
||||
import ThreadMessagesView from '../views/ThreadMessagesView';
|
||||
|
@ -116,6 +117,7 @@ const ChatsStackNavigator = () => {
|
|||
options={NotificationPrefView.navigationOptions}
|
||||
/>
|
||||
<ChatsStack.Screen name='ForwardLivechatView' component={ForwardLivechatView} />
|
||||
<ChatsStack.Screen name='CloseLivechatView' component={CloseLivechatView} />
|
||||
<ChatsStack.Screen name='LivechatEditView' component={LivechatEditView} options={LivechatEditView.navigationOptions} />
|
||||
<ChatsStack.Screen name='PickerView' component={PickerView} options={PickerView.navigationOptions} />
|
||||
<ChatsStack.Screen
|
||||
|
|
|
@ -27,6 +27,7 @@ import AutoTranslateView from '../../views/AutoTranslateView';
|
|||
import DirectoryView from '../../views/DirectoryView';
|
||||
import NotificationPrefView from '../../views/NotificationPreferencesView';
|
||||
import ForwardLivechatView from '../../views/ForwardLivechatView';
|
||||
import CloseLivechatView from '../../views/CloseLivechatView';
|
||||
import CannedResponsesListView from '../../views/CannedResponsesListView';
|
||||
import CannedResponseDetail from '../../views/CannedResponseDetail';
|
||||
import LivechatEditView from '../../views/LivechatEditView';
|
||||
|
@ -156,6 +157,7 @@ const ModalStackNavigator = React.memo(({ navigation }: INavigation) => {
|
|||
options={NotificationPrefView.navigationOptions}
|
||||
/>
|
||||
<ModalStack.Screen name='ForwardLivechatView' component={ForwardLivechatView} />
|
||||
<ModalStack.Screen name='CloseLivechatView' component={CloseLivechatView} />
|
||||
<ModalStack.Screen name='CannedResponsesListView' component={CannedResponsesListView} />
|
||||
<ModalStack.Screen name='CannedResponseDetail' component={CannedResponseDetail} />
|
||||
<ModalStack.Screen name='LivechatEditView' component={LivechatEditView} options={LivechatEditView.navigationOptions} />
|
||||
|
|
|
@ -4,6 +4,8 @@ import { NavigatorScreenParams } from '@react-navigation/core';
|
|||
import { IAttachment } from '../../definitions/IAttachment';
|
||||
import { IMessage } from '../../definitions/IMessage';
|
||||
import { ISubscription, SubscriptionType, TSubscriptionModel } from '../../definitions/ISubscription';
|
||||
import { ILivechatDepartment } from '../../definitions/ILivechatDepartment';
|
||||
import { ILivechatTag } from '../../definitions/ILivechatTag';
|
||||
|
||||
export type MasterDetailChatsStackParamList = {
|
||||
RoomView: {
|
||||
|
@ -111,6 +113,12 @@ export type ModalStackParamList = {
|
|||
ForwardLivechatView: {
|
||||
rid: string;
|
||||
};
|
||||
CloseLivechatView: {
|
||||
rid: string;
|
||||
departmentId?: string;
|
||||
departmentInfo?: ILivechatDepartment;
|
||||
tagsList?: ILivechatTag[];
|
||||
};
|
||||
CannedResponsesListView: {
|
||||
rid: string;
|
||||
};
|
||||
|
|
|
@ -11,6 +11,8 @@ import { ICannedResponse } from '../definitions/ICannedResponse';
|
|||
import { TDataSelect } from '../definitions/IDataSelect';
|
||||
import { ModalStackParamList } from './MasterDetailStack/types';
|
||||
import { TThreadModel } from '../definitions';
|
||||
import { ILivechatDepartment } from '../definitions/ILivechatDepartment';
|
||||
import { ILivechatTag } from '../definitions/ILivechatTag';
|
||||
|
||||
export type ChatsStackParamList = {
|
||||
ModalStackNavigator: NavigatorScreenParams<ModalStackParamList>;
|
||||
|
@ -114,6 +116,12 @@ export type ChatsStackParamList = {
|
|||
ForwardLivechatView: {
|
||||
rid: string;
|
||||
};
|
||||
CloseLivechatView: {
|
||||
rid: string;
|
||||
departmentId?: string;
|
||||
departmentInfo?: ILivechatDepartment;
|
||||
tagsList?: ILivechatTag[];
|
||||
};
|
||||
LivechatEditView: {
|
||||
room: ISubscription;
|
||||
roomUser: any; // TODO: Change
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
import React, { useState, useLayoutEffect } from 'react';
|
||||
import { StyleSheet, ScrollView, Text } from 'react-native';
|
||||
import { BlockContext } from '@rocket.chat/ui-kit';
|
||||
|
||||
import { IBaseScreen } from '../definitions';
|
||||
import I18n from '../i18n';
|
||||
import { ChatsStackParamList } from '../stacks/types';
|
||||
import { useTheme } from '../theme';
|
||||
import KeyboardView from '../containers/KeyboardView';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import { FormTextInput } from '../containers/TextInput';
|
||||
import Button from '../containers/Button';
|
||||
import { useAppSelector } from '../lib/hooks';
|
||||
import sharedStyles from './Styles';
|
||||
import scrollPersistTaps from '../lib/methods/helpers/scrollPersistTaps';
|
||||
import { MultiSelect } from '../containers/UIKit/MultiSelect';
|
||||
import { closeLivechat } from '../lib/methods/helpers/closeLivechat';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 16
|
||||
},
|
||||
subtitleText: {
|
||||
marginBottom: 10,
|
||||
fontSize: 14,
|
||||
...sharedStyles.textSemibold
|
||||
},
|
||||
buttonMarginVertical: { marginVertical: 20 }
|
||||
});
|
||||
|
||||
const CloseLivechatView = ({ navigation, route }: IBaseScreen<ChatsStackParamList, 'CloseLivechatView'>) => {
|
||||
const rid = route.params?.rid;
|
||||
const departmentInfo = route.params?.departmentInfo;
|
||||
const tagsList = route.params?.tagsList;
|
||||
const requestTags = departmentInfo?.requestTagBeforeClosingChat;
|
||||
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const [tagParamSelected, setTagParamSelected] = useState<string[]>([]);
|
||||
|
||||
const { colors } = useTheme();
|
||||
|
||||
const { isMasterDetail, livechatRequestComment } = useAppSelector(state => ({
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
livechatRequestComment: state.settings.Livechat_request_comment_when_closing_conversation as boolean
|
||||
}));
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
title: I18n.t('Close_Chat')
|
||||
});
|
||||
}, [navigation]);
|
||||
|
||||
const canSubmit = () => {
|
||||
if (!requestTags && !livechatRequestComment) {
|
||||
return true;
|
||||
}
|
||||
if (requestTags && tagParamSelected.length > 0 && !livechatRequestComment) {
|
||||
return true;
|
||||
}
|
||||
if (livechatRequestComment && !!inputValue && !requestTags) {
|
||||
return true;
|
||||
}
|
||||
if (livechatRequestComment && requestTags && tagParamSelected.length > 0 && !!inputValue) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
closeLivechat({ rid, isMasterDetail, comment: inputValue, tags: tagParamSelected });
|
||||
};
|
||||
|
||||
return (
|
||||
<KeyboardView
|
||||
style={{ backgroundColor: colors.auxiliaryBackground }}
|
||||
contentContainerStyle={sharedStyles.container}
|
||||
keyboardVerticalOffset={128}>
|
||||
<ScrollView {...scrollPersistTaps} style={styles.container}>
|
||||
<SafeAreaView>
|
||||
<FormTextInput
|
||||
label={I18n.t('Please_add_a_comment')}
|
||||
defaultValue={''}
|
||||
onChangeText={text => setInputValue(text)}
|
||||
onSubmitEditing={() => {
|
||||
if (canSubmit()) {
|
||||
submit();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
{requestTags ? (
|
||||
<>
|
||||
<Text style={[styles.subtitleText, { color: colors.titleText }]}>{I18n.t('Tags')}</Text>
|
||||
<MultiSelect
|
||||
options={tagsList?.map(({ name }) => ({ text: { text: name }, value: name }))}
|
||||
onChange={({ value }: { value: string[] }) => {
|
||||
setTagParamSelected(value);
|
||||
}}
|
||||
placeholder={{ text: I18n.t('Select_tags') }}
|
||||
value={tagParamSelected}
|
||||
context={BlockContext.FORM}
|
||||
multiselect
|
||||
inputStyle={{ borderColor: colors.separatorColor, borderWidth: 2 }}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
<Button
|
||||
title={I18n.t('Close')}
|
||||
onPress={submit}
|
||||
disabled={!canSubmit()}
|
||||
backgroundColor={colors.dangerColor}
|
||||
type='primary'
|
||||
style={styles.buttonMarginVertical}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
</ScrollView>
|
||||
</KeyboardView>
|
||||
);
|
||||
};
|
||||
|
||||
export default CloseLivechatView;
|
|
@ -46,10 +46,11 @@ import {
|
|||
import { Services } from '../../lib/services';
|
||||
import { getSubscriptionByRoomId } from '../../lib/database/services/Subscription';
|
||||
import { IActionSheetProvider, withActionSheet } from '../../containers/ActionSheet';
|
||||
import CloseLivechatSheet from '../../ee/omnichannel/containers/CloseLivechatSheet';
|
||||
import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types';
|
||||
import { closeLivechat } from '../../lib/methods/helpers/closeLivechat';
|
||||
import { videoConfStartAndJoin } from '../../lib/methods/videoConf';
|
||||
import { ILivechatDepartment } from '../../definitions/ILivechatDepartment';
|
||||
import { ILivechatTag } from '../../definitions/ILivechatTag';
|
||||
|
||||
interface IOnPressTouch {
|
||||
<T extends keyof ChatsStackParamList>(item: { route?: T; params?: ChatsStackParamList[T]; event?: Function }): void;
|
||||
|
@ -376,29 +377,31 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
);
|
||||
};
|
||||
|
||||
closeLivechat = () => {
|
||||
closeLivechat = async () => {
|
||||
const {
|
||||
room: { rid }
|
||||
room: { rid, departmentId }
|
||||
} = this.state;
|
||||
const { livechatRequestComment, showActionSheet, hideActionSheet, isMasterDetail } = this.props;
|
||||
const { livechatRequestComment, isMasterDetail, navigation } = this.props;
|
||||
let departmentInfo: ILivechatDepartment | undefined;
|
||||
let tagsList: ILivechatTag[] | undefined;
|
||||
|
||||
if (!livechatRequestComment) {
|
||||
if (departmentId) {
|
||||
const result = await Services.getDepartmentInfo(departmentId);
|
||||
if (result.success) {
|
||||
departmentInfo = result.department as ILivechatDepartment;
|
||||
}
|
||||
}
|
||||
|
||||
if (departmentInfo?.requestTagBeforeClosingChat) {
|
||||
tagsList = await Services.getTagsList();
|
||||
}
|
||||
|
||||
if (!livechatRequestComment && !departmentInfo?.requestTagBeforeClosingChat) {
|
||||
const comment = I18n.t('Chat_closed_by_agent');
|
||||
return closeLivechat({ rid, isMasterDetail, comment });
|
||||
}
|
||||
|
||||
showActionSheet({
|
||||
children: (
|
||||
<CloseLivechatSheet
|
||||
onSubmit={(comment: string) => {
|
||||
hideActionSheet();
|
||||
closeLivechat({ rid, isMasterDetail, comment });
|
||||
}}
|
||||
onCancel={() => hideActionSheet()}
|
||||
/>
|
||||
),
|
||||
headerHeight: 225
|
||||
});
|
||||
navigation.navigate('CloseLivechatView', { rid, departmentId, departmentInfo, tagsList });
|
||||
};
|
||||
|
||||
placeOnHoldLivechat = () => {
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Observable, Subscription } from 'rxjs';
|
|||
import { Dispatch } from 'redux';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
|
||||
import { ILivechatTag } from '../../definitions/ILivechatTag';
|
||||
import * as HeaderButton from '../../containers/HeaderButton';
|
||||
import database from '../../lib/database';
|
||||
import { getUserSelector } from '../../selectors/login';
|
||||
|
@ -17,7 +18,8 @@ import i18n from '../../i18n';
|
|||
import { showConfirmationAlert, showErrorAlert } from '../../lib/methods/helpers';
|
||||
import { onHoldLivechat, returnLivechat } from '../../lib/services/restApi';
|
||||
import { closeLivechat as closeLivechatService } from '../../lib/methods/helpers/closeLivechat';
|
||||
import CloseLivechatSheet from '../../ee/omnichannel/containers/CloseLivechatSheet';
|
||||
import { Services } from '../../lib/services';
|
||||
import { ILivechatDepartment } from '../../definitions/ILivechatDepartment';
|
||||
|
||||
interface IRightButtonsProps extends IActionSheetProvider {
|
||||
userId?: string;
|
||||
|
@ -40,6 +42,7 @@ interface IRightButtonsProps extends IActionSheetProvider {
|
|||
canPlaceLivechatOnHold: boolean;
|
||||
};
|
||||
livechatRequestComment: boolean;
|
||||
departmentId?: string;
|
||||
}
|
||||
|
||||
interface IRigthButtonsState {
|
||||
|
@ -214,35 +217,41 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
});
|
||||
};
|
||||
|
||||
closeLivechat = () => {
|
||||
const { rid, livechatRequestComment, showActionSheet, hideActionSheet, isMasterDetail } = this.props;
|
||||
closeLivechat = async () => {
|
||||
const { rid, departmentId } = this.props;
|
||||
const { livechatRequestComment, isMasterDetail, navigation } = this.props;
|
||||
let departmentInfo: ILivechatDepartment | undefined;
|
||||
let tagsList: ILivechatTag[] | undefined;
|
||||
|
||||
hideActionSheet();
|
||||
if (departmentId) {
|
||||
const result = await Services.getDepartmentInfo(departmentId);
|
||||
if (result.success) {
|
||||
departmentInfo = result.department as ILivechatDepartment;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (!livechatRequestComment) {
|
||||
if (departmentInfo?.requestTagBeforeClosingChat) {
|
||||
tagsList = await Services.getTagsList();
|
||||
}
|
||||
|
||||
if (!livechatRequestComment && !departmentInfo?.requestTagBeforeClosingChat) {
|
||||
const comment = i18n.t('Chat_closed_by_agent');
|
||||
return closeLivechatService({ rid, isMasterDetail, comment });
|
||||
}
|
||||
|
||||
showActionSheet({
|
||||
children: (
|
||||
<CloseLivechatSheet
|
||||
onSubmit={(comment: string) => {
|
||||
hideActionSheet();
|
||||
closeLivechatService({ rid, isMasterDetail, comment });
|
||||
}}
|
||||
onCancel={() => hideActionSheet()}
|
||||
/>
|
||||
),
|
||||
headerHeight: 225
|
||||
if (isMasterDetail) {
|
||||
navigation.navigate('ModalStackNavigator', {
|
||||
screen: 'CloseLivechatView',
|
||||
params: { rid, departmentId, departmentInfo, tagsList }
|
||||
});
|
||||
}, 300);
|
||||
} else {
|
||||
navigation.navigate('CloseLivechatView', { rid, departmentId, departmentInfo, tagsList });
|
||||
}
|
||||
};
|
||||
|
||||
showMoreActions = () => {
|
||||
logEvent(events.ROOM_SHOW_MORE_ACTIONS);
|
||||
const { showActionSheet, rid, navigation, omnichannelPermissions } = this.props;
|
||||
const { showActionSheet, rid, navigation, omnichannelPermissions, isMasterDetail } = this.props;
|
||||
|
||||
const options = [] as TActionSheetOptionsItem[];
|
||||
if (omnichannelPermissions.canPlaceLivechatOnHold) {
|
||||
|
@ -257,7 +266,16 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
options.push({
|
||||
title: i18n.t('Forward_Chat'),
|
||||
icon: 'chat-forward',
|
||||
onPress: () => navigation.navigate('ForwardLivechatView', { rid })
|
||||
onPress: () => {
|
||||
if (isMasterDetail) {
|
||||
navigation.navigate('ModalStackNavigator', {
|
||||
screen: 'ForwardLivechatView',
|
||||
params: { rid }
|
||||
});
|
||||
} else {
|
||||
navigation.navigate('ForwardLivechatView', { rid });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -559,6 +559,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
let avatar: string | undefined;
|
||||
let visitor: IVisitor | undefined;
|
||||
let sourceType: IOmnichannelSource | undefined;
|
||||
let departmentId: string | undefined;
|
||||
if ('id' in room) {
|
||||
subtitle = room.topic;
|
||||
t = room.t;
|
||||
|
@ -568,6 +569,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
({ id: userId, token } = user);
|
||||
avatar = room.name;
|
||||
visitor = room.visitor;
|
||||
departmentId = room.departmentId;
|
||||
}
|
||||
|
||||
if ('source' in room) {
|
||||
|
@ -632,6 +634,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
encrypted={encrypted}
|
||||
navigation={navigation}
|
||||
toggleFollowThread={this.toggleFollowThread}
|
||||
departmentId={departmentId}
|
||||
/>
|
||||
)
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue