@webinex/chatify 2.0.0-alpha10 → 2.0.0-alpha13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Chatify-DGRV4QKP.js → Chatify-CwAfN1wu.js} +310 -117
- package/dist/Chatify-CwAfN1wu.js.map +1 -0
- package/dist/Chatify.css +54 -7
- package/dist/audit.js +2 -2
- package/dist/audit.js.map +1 -1
- package/dist/index.js +82 -75
- package/dist/types/audit/auditApi.d.ts +5 -1
- package/dist/types/core/api/api.d.ts +57 -17206
- package/dist/types/core/client.d.ts +4 -1
- package/dist/types/ui/ChatGroup/AutoReply/AutoReplyButton.d.ts +1 -0
- package/dist/types/ui/ChatGroup/AutoReply/AutoReplyForm.d.ts +12 -0
- package/dist/types/ui/ChatGroup/AutoReply/AutoReplyPanel.d.ts +1 -0
- package/dist/types/ui/ChatGroup/AutoReply/AutoReplyPeriodInput.d.ts +4 -0
- package/dist/types/ui/ChatGroup/AutoReply/AutoReplyTextInput.d.ts +4 -0
- package/dist/types/ui/ChatGroup/AutoReply/index.d.ts +17 -0
- package/dist/types/ui/ChatGroup/ChatGroupContext.d.ts +2 -1
- package/dist/types/ui/ChatGroup/ChatGroupPanel.d.ts +2 -1
- package/dist/types/ui/ChatGroup/Layout/ChatGroupActions.d.ts +1 -0
- package/dist/types/ui/ChatGroup/Layout/index.d.ts +3 -0
- package/dist/types/ui/ChatGroup/index.d.ts +1 -0
- package/dist/types/ui/common/Icon.d.ts +1 -0
- package/dist/types/ui/localizer.d.ts +15 -0
- package/package.json +1 -1
- package/src/audit/AuditSearch.tsx +1 -1
- package/src/core/api/api.ts +24 -4
- package/src/core/client.ts +13 -2
- package/src/styles/index.scss +65 -6
- package/src/ui/Chat/Members/ChatMembersPanel.tsx +2 -2
- package/src/ui/ChatGroup/AutoReply/AutoReplyButton.tsx +21 -0
- package/src/ui/ChatGroup/AutoReply/AutoReplyForm.tsx +50 -0
- package/src/ui/ChatGroup/AutoReply/AutoReplyPanel.tsx +94 -0
- package/src/ui/ChatGroup/AutoReply/AutoReplyPeriodInput.tsx +22 -0
- package/src/ui/ChatGroup/AutoReply/AutoReplyTextInput.tsx +22 -0
- package/src/ui/ChatGroup/AutoReply/index.ts +19 -0
- package/src/ui/ChatGroup/ChatGroupContext.tsx +12 -1
- package/src/ui/ChatGroup/ChatGroupPanel.tsx +2 -0
- package/src/ui/ChatGroup/Create/CreateChatMemberInput.tsx +1 -1
- package/src/ui/ChatGroup/Layout/ChatGroupActions.tsx +15 -0
- package/src/ui/ChatGroup/Layout/ChatGroupAside.tsx +2 -2
- package/src/ui/ChatGroup/Layout/ChatGroupMain.tsx +2 -0
- package/src/ui/ChatGroup/Layout/index.ts +3 -0
- package/src/ui/ChatGroup/index.ts +1 -0
- package/src/ui/common/Icon.tsx +2 -0
- package/src/ui/localizer.tsx +29 -0
- package/dist/Chatify-DGRV4QKP.js.map +0 -1
|
@@ -52,7 +52,10 @@ export declare class ChatifyClient {
|
|
|
52
52
|
subscribe: <TMethod extends ChatifySignalRMethod>(method: TMethod, subscriber: (args: ChatifySignalRArgsByMethod[TMethod]) => void) => () => ((args: any[]) => void)[];
|
|
53
53
|
subscribeReconnect: (subscriber: () => any) => () => (() => void)[];
|
|
54
54
|
get axios(): AxiosInstance;
|
|
55
|
-
accounts: (
|
|
55
|
+
accounts: (args: {
|
|
56
|
+
ids?: string[];
|
|
57
|
+
}) => Promise<Account[]>;
|
|
58
|
+
currentUserAccount: () => Promise<Account>;
|
|
56
59
|
updateAccount: (request: UpdateAccountRequest) => Promise<void>;
|
|
57
60
|
chats: () => Promise<ChatListItem[]>;
|
|
58
61
|
chat: (id: string) => Promise<Chat>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const AutoReplyButton: import('../../../index.ts').Customizable<import('react').ComponentType<unknown>>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Dayjs } from 'dayjs';
|
|
2
|
+
export interface AutoReplyFormValue {
|
|
3
|
+
period: [Dayjs, Dayjs];
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
export interface AutoReplyFormProps {
|
|
7
|
+
value: AutoReplyFormValue;
|
|
8
|
+
onSubmit: (value: AutoReplyFormValue) => void;
|
|
9
|
+
busy?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const AUTO_REPLY_FORM_INITIAL_VALUE: AutoReplyFormValue;
|
|
12
|
+
export declare const AutoReplyForm: import('../../../index.ts').Customizable<import('react').ComponentType<AutoReplyFormProps>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const AutoReplyPanel: import('../../../index.ts').Customizable<import('react').ComponentType<unknown>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AutoReplyButton } from './AutoReplyButton';
|
|
2
|
+
import { AutoReplyForm } from './AutoReplyForm';
|
|
3
|
+
import { AutoReplyPanel } from './AutoReplyPanel';
|
|
4
|
+
import { AutoReplyPeriodInput } from './AutoReplyPeriodInput';
|
|
5
|
+
import { AutoReplyTextInput } from './AutoReplyTextInput';
|
|
6
|
+
export * from './AutoReplyButton';
|
|
7
|
+
export * from './AutoReplyForm';
|
|
8
|
+
export * from './AutoReplyPanel';
|
|
9
|
+
export * from './AutoReplyPeriodInput';
|
|
10
|
+
export * from './AutoReplyTextInput';
|
|
11
|
+
export interface AutoReplyCustomizeValue {
|
|
12
|
+
AutoReplyButton?: typeof AutoReplyButton.Component | null;
|
|
13
|
+
AutoReplyForm?: typeof AutoReplyForm.Component | null;
|
|
14
|
+
AutoReplyPanel?: typeof AutoReplyPanel.Component | null;
|
|
15
|
+
AutoReplyPeriodInput?: typeof AutoReplyPeriodInput.Component | null;
|
|
16
|
+
AutoReplyTextInput?: typeof AutoReplyTextInput.Component | null;
|
|
17
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { PropsWithChildren } from 'react';
|
|
2
2
|
export interface ChatGroupContext {
|
|
3
|
-
view: 'chat' | 'new-chat' | null;
|
|
3
|
+
view: 'chat' | 'new-chat' | 'auto-reply' | null;
|
|
4
4
|
chatId: string | null;
|
|
5
5
|
showMembers: boolean;
|
|
6
6
|
none(): void;
|
|
7
7
|
openChat(chatId: string): void;
|
|
8
8
|
toggleNewChat(): void;
|
|
9
9
|
toggleMembers(): void;
|
|
10
|
+
toggleAutoReply(): void;
|
|
10
11
|
}
|
|
11
12
|
export declare function useChatGroupContext(): ChatGroupContext;
|
|
12
13
|
export declare function ChatGroupContext(props: PropsWithChildren<{}>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,7 +4,8 @@ import { CreateChatPanelCustomizeValue } from './Create';
|
|
|
4
4
|
import { ChatGroupLayoutCustomizeValue } from './Layout';
|
|
5
5
|
import { ChatListPanelCustomizeValue } from './List';
|
|
6
6
|
import { ChatViewCustomizeValue } from '../Chat';
|
|
7
|
-
|
|
7
|
+
import { AutoReplyCustomizeValue } from './AutoReply';
|
|
8
|
+
export interface ChatGroupCustomizeValue extends ChatViewCustomizeValue, AutoReplyCustomizeValue, CreateChatPanelCustomizeValue, ChatListPanelCustomizeValue, ChatGroupLayoutCustomizeValue {
|
|
8
9
|
}
|
|
9
10
|
export interface ChatifyProps {
|
|
10
11
|
className?: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ChatGroupActions: import('../../../index.ts').Customizable<import('react').ComponentType<unknown>>;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import { ChatGroupActions } from './ChatGroupActions';
|
|
1
2
|
import { ChatGroupAside } from './ChatGroupAside';
|
|
2
3
|
import { ChatGroupHeader } from './ChatGroupHeader';
|
|
3
4
|
import { ChatGroupFooter } from './ChatGroupFooter';
|
|
4
5
|
import { ChatGroupMain } from './ChatGroupMain';
|
|
5
6
|
import { ChatGroupBody } from './ChatGroupBody';
|
|
7
|
+
export * from './ChatGroupActions';
|
|
6
8
|
export * from './ChatGroupAside';
|
|
7
9
|
export * from './ChatGroupHeader';
|
|
8
10
|
export * from './ChatGroupFooter';
|
|
9
11
|
export * from './ChatGroupMain';
|
|
10
12
|
export * from './ChatGroupBody';
|
|
11
13
|
export interface ChatGroupLayoutCustomizeValue {
|
|
14
|
+
ChatGroupActions?: typeof ChatGroupActions.Component | null;
|
|
12
15
|
ChatGroupAside?: typeof ChatGroupAside.Component | null;
|
|
13
16
|
ChatGroupHeader?: typeof ChatGroupHeader.Component | null;
|
|
14
17
|
ChatGroupFooter?: typeof ChatGroupFooter.Component | null;
|
|
@@ -17,5 +17,6 @@ export declare const ICONS: {
|
|
|
17
17
|
unwatch: import('react').ForwardRefExoticComponent<Omit<import('@ant-design/icons/lib/components/AntdIcon').AntdIconProps, "ref"> & import('react').RefAttributes<HTMLSpanElement>>;
|
|
18
18
|
'delete-file': import('react').ForwardRefExoticComponent<Omit<import('@ant-design/icons/lib/components/AntdIcon').AntdIconProps, "ref"> & import('react').RefAttributes<HTMLSpanElement>>;
|
|
19
19
|
'open-file': import('react').ForwardRefExoticComponent<Omit<import('@ant-design/icons/lib/components/AntdIcon').AntdIconProps, "ref"> & import('react').RefAttributes<HTMLSpanElement>>;
|
|
20
|
+
settings: import('react').ForwardRefExoticComponent<Omit<import('@ant-design/icons/lib/components/AntdIcon').AntdIconProps, "ref"> & import('react').RefAttributes<HTMLSpanElement>>;
|
|
20
21
|
};
|
|
21
22
|
export declare const Icon: import('../../index.ts').Customizable<import('react').ComponentType<IconProps>>;
|
|
@@ -37,6 +37,21 @@ export interface LocalizerBase {
|
|
|
37
37
|
chatList: {
|
|
38
38
|
topShown: (count: number) => string;
|
|
39
39
|
};
|
|
40
|
+
autoReply: {
|
|
41
|
+
buttonTitle: () => string;
|
|
42
|
+
title: () => React.ReactNode;
|
|
43
|
+
period: {
|
|
44
|
+
label: () => React.ReactNode;
|
|
45
|
+
required: () => string;
|
|
46
|
+
format: () => string;
|
|
47
|
+
};
|
|
48
|
+
text: {
|
|
49
|
+
label: () => React.ReactNode;
|
|
50
|
+
required: () => string;
|
|
51
|
+
};
|
|
52
|
+
submitBtn: () => React.ReactNode;
|
|
53
|
+
clearBtn: () => React.ReactNode;
|
|
54
|
+
};
|
|
40
55
|
}
|
|
41
56
|
export interface Localizer extends LocalizerBase {
|
|
42
57
|
}
|
package/package.json
CHANGED
|
@@ -42,7 +42,7 @@ export const AuditSearch = customize('AuditSearch', (props: AuditSearchProps) =>
|
|
|
42
42
|
const { className, onSearch } = props;
|
|
43
43
|
const [searchValue, setSearchValue] = useState('');
|
|
44
44
|
const [values, setValues] = useState<Value[]>([]);
|
|
45
|
-
const { data: accounts, isLoading } = chatifyApi.useGetAccountListQuery();
|
|
45
|
+
const { data: accounts, isLoading } = chatifyApi.useGetAccountListQuery({});
|
|
46
46
|
const options = useOptions(accounts, searchValue);
|
|
47
47
|
const localizer = useLocalizer();
|
|
48
48
|
|
package/src/core/api/api.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_MESSAGE_LIST_TAKE, __baseApi, __settings } from './baseApi';
|
|
1
|
+
import { ChatifyApiSettings, DEFAULT_MESSAGE_LIST_TAKE, __baseApi, __settings } from './baseApi';
|
|
2
2
|
import { useSelector } from 'react-redux';
|
|
3
3
|
import {
|
|
4
4
|
Account,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
Thread,
|
|
13
13
|
ThreadMessage,
|
|
14
14
|
ThreadWatchListItem,
|
|
15
|
+
UpdateAccountRequest,
|
|
15
16
|
calcThreadListUnreadCount,
|
|
16
17
|
chatId,
|
|
17
18
|
parseThreadMessageId,
|
|
@@ -50,11 +51,24 @@ const __chatifyApi = __baseApi.injectEndpoints({
|
|
|
50
51
|
// ============== ACCOUNT ======================
|
|
51
52
|
// ====================================================
|
|
52
53
|
|
|
53
|
-
getAccountList: builder.query<Account[],
|
|
54
|
-
queryFn: async () => ({ data: await __settings.client.accounts() }),
|
|
54
|
+
getAccountList: builder.query<Account[], { ids?: string[] }>({
|
|
55
|
+
queryFn: async (args) => ({ data: await __settings.client.accounts(args) }),
|
|
55
56
|
providesTags: ['account'],
|
|
56
57
|
}),
|
|
57
58
|
|
|
59
|
+
geCurrentUserAccount: builder.query<Account | null, void>({
|
|
60
|
+
queryFn: async () => ({ data: await __settings.client.currentUserAccount() }),
|
|
61
|
+
providesTags: ['account'],
|
|
62
|
+
}),
|
|
63
|
+
|
|
64
|
+
updateAccount: builder.mutation<void, UpdateAccountRequest>({
|
|
65
|
+
queryFn: async (request) => {
|
|
66
|
+
await __settings.client.updateAccount(request);
|
|
67
|
+
return { data: null! };
|
|
68
|
+
},
|
|
69
|
+
invalidatesTags: ['account'],
|
|
70
|
+
}),
|
|
71
|
+
|
|
58
72
|
// ====================================================
|
|
59
73
|
// ================ CHAT =======================
|
|
60
74
|
// ====================================================
|
|
@@ -648,7 +662,13 @@ export function useUnreadThreadMessageCount() {
|
|
|
648
662
|
return [count, state] as const;
|
|
649
663
|
}
|
|
650
664
|
|
|
651
|
-
|
|
665
|
+
type ChatifyApi = typeof __chatifyApi & {
|
|
666
|
+
settings: ChatifyApiSettings;
|
|
667
|
+
useChatListItem: typeof useChatListItem;
|
|
668
|
+
useUnreadThreadMessageCount: typeof useUnreadThreadMessageCount;
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
export const chatifyApi: ChatifyApi = Object.assign(__chatifyApi, {
|
|
652
672
|
settings: __settings,
|
|
653
673
|
useChatListItem,
|
|
654
674
|
useUnreadThreadMessageCount,
|
package/src/core/client.ts
CHANGED
|
@@ -164,8 +164,19 @@ export class ChatifyClient {
|
|
|
164
164
|
return this._config.axios;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
public accounts = async () => {
|
|
168
|
-
const
|
|
167
|
+
public accounts = async (args: { ids?: string[] }) => {
|
|
168
|
+
const searchParams = new URLSearchParams();
|
|
169
|
+
|
|
170
|
+
args?.ids?.forEach((id) => {
|
|
171
|
+
searchParams.append('ids', encodeURIComponent(id));
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const { data } = await this.axios.get<Account[]>(`account?${searchParams.toString()}`);
|
|
175
|
+
return data;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
public currentUserAccount = async () => {
|
|
179
|
+
const { data } = await this.axios.get<Account>('account/me');
|
|
169
180
|
return data;
|
|
170
181
|
};
|
|
171
182
|
|
package/src/styles/index.scss
CHANGED
|
@@ -83,18 +83,51 @@
|
|
|
83
83
|
padding-inline: 0.5rem;
|
|
84
84
|
margin-bottom: 1rem;
|
|
85
85
|
|
|
86
|
-
.wxchtf-add-btn
|
|
86
|
+
.wxchtf-add-btn,
|
|
87
|
+
.wxchtf-add-btn-settings {
|
|
87
88
|
border: none;
|
|
88
89
|
background-color: #e4f7f7;
|
|
89
90
|
height: 50px;
|
|
90
|
-
padding: 0;
|
|
91
91
|
line-height: 50px;
|
|
92
|
-
min-width: 150px;
|
|
93
|
-
border-radius: 50px;
|
|
94
92
|
font-weight: 600;
|
|
95
93
|
opacity: 0.9;
|
|
96
94
|
box-shadow: none;
|
|
97
95
|
}
|
|
96
|
+
|
|
97
|
+
> .wxchtf-add-btn {
|
|
98
|
+
padding: 0 24px;
|
|
99
|
+
min-width: 150px;
|
|
100
|
+
border-radius: 50px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
> .wxchtf-add-btn-settings {
|
|
104
|
+
padding: 0 16px;
|
|
105
|
+
min-width: 50px;
|
|
106
|
+
border-radius: 50px;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
> .wxchtf-add-btn-group {
|
|
110
|
+
display: inline-flex;
|
|
111
|
+
|
|
112
|
+
.wxchtf-add-btn-wrapper {
|
|
113
|
+
width: auto;
|
|
114
|
+
padding-inline: 0;
|
|
115
|
+
margin-bottom: 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.wxchtf-add-btn {
|
|
119
|
+
padding: 0 18px;
|
|
120
|
+
min-width: 120px;
|
|
121
|
+
border-radius: 50px 0 0 50px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.wxchtf-add-btn-settings {
|
|
125
|
+
padding: 0 14px;
|
|
126
|
+
min-width: 44px;
|
|
127
|
+
border-radius: 0 50px 50px 0;
|
|
128
|
+
border-left: 1px solid rgba(0, 0, 0, 0.06);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
98
131
|
}
|
|
99
132
|
}
|
|
100
133
|
|
|
@@ -108,7 +141,8 @@
|
|
|
108
141
|
z-index: 2;
|
|
109
142
|
min-width: 0;
|
|
110
143
|
|
|
111
|
-
.wxchtf-create-chat-panel
|
|
144
|
+
.wxchtf-create-chat-panel,
|
|
145
|
+
.wxchtf-auto-reply-panel {
|
|
112
146
|
display: flex;
|
|
113
147
|
flex-flow: column nowrap;
|
|
114
148
|
justify-content: center;
|
|
@@ -116,7 +150,8 @@
|
|
|
116
150
|
height: 100%;
|
|
117
151
|
position: relative;
|
|
118
152
|
|
|
119
|
-
.wxchtf-create-chat-panel-close
|
|
153
|
+
.wxchtf-create-chat-panel-close,
|
|
154
|
+
.wxchtf-auto-reply-panel-close {
|
|
120
155
|
position: absolute;
|
|
121
156
|
right: 25px;
|
|
122
157
|
top: 25px;
|
|
@@ -126,7 +161,31 @@
|
|
|
126
161
|
padding: 2rem;
|
|
127
162
|
max-width: 700px;
|
|
128
163
|
width: 100%;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
129
166
|
|
|
167
|
+
.wxchtf-auto-reply-panel {
|
|
168
|
+
.wxchtf-auto-reply-panel-header {
|
|
169
|
+
width: 100%;
|
|
170
|
+
max-width: 700px;
|
|
171
|
+
padding: 0 2rem;
|
|
172
|
+
margin-bottom: 0.5rem;
|
|
173
|
+
display: flex;
|
|
174
|
+
align-items: center;
|
|
175
|
+
justify-content: space-between;
|
|
176
|
+
|
|
177
|
+
h3 {
|
|
178
|
+
margin: 0;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.wxchtf-auto-reply-panel-clear {
|
|
182
|
+
padding: 0;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.wxchtf-create-chat-panel {
|
|
188
|
+
form {
|
|
130
189
|
.wxchtf-create-chat-member-input-list {
|
|
131
190
|
max-height: 15rem;
|
|
132
191
|
overflow-y: auto;
|
|
@@ -32,7 +32,7 @@ function useRemove(chatId: string, accountId: string, deleteHistory: boolean) {
|
|
|
32
32
|
const ChatMemberListItem = customize('ChatMemberListItem', (props: ChatMemberListItemProps) => {
|
|
33
33
|
const { chatId } = props;
|
|
34
34
|
const { data: chat } = chatifyApi.useGetChatQuery({ id: chatId });
|
|
35
|
-
const { data: accounts } = chatifyApi.useGetAccountListQuery();
|
|
35
|
+
const { data: accounts } = chatifyApi.useGetAccountListQuery({});
|
|
36
36
|
const account = accounts!.find((x) => x.id === props.id)!;
|
|
37
37
|
const isMember = chat!.members.some((x) => x.id === account.id);
|
|
38
38
|
const [onAddWithoutHistory] = useAdd(chatId, account.id, false);
|
|
@@ -82,7 +82,7 @@ const ChatMemberListItem = customize('ChatMemberListItem', (props: ChatMemberLis
|
|
|
82
82
|
export const ChatMembersPanel = customize('ChatMembersPanel', () => {
|
|
83
83
|
const { id } = useChatContext();
|
|
84
84
|
const { data: chat } = chatifyApi.useGetChatQuery({ id });
|
|
85
|
-
const { data: accounts } = chatifyApi.useGetAccountListQuery();
|
|
85
|
+
const { data: accounts } = chatifyApi.useGetAccountListQuery({});
|
|
86
86
|
const ordered = useMemo(
|
|
87
87
|
() =>
|
|
88
88
|
accounts
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Button } from 'antd';
|
|
2
|
+
import { customize } from '../../customize';
|
|
3
|
+
import { useChatGroupContext } from '../ChatGroupContext';
|
|
4
|
+
import { useLocalizer } from '../../localizer';
|
|
5
|
+
import { Icon } from '../../common/Icon';
|
|
6
|
+
|
|
7
|
+
export const AutoReplyButton = customize('AutoReplyButton', () => {
|
|
8
|
+
const { toggleAutoReply } = useChatGroupContext();
|
|
9
|
+
const localizer = useLocalizer();
|
|
10
|
+
const titleText = localizer.autoReply.buttonTitle();
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Button
|
|
14
|
+
className="wxchtf-add-btn-settings"
|
|
15
|
+
onClick={toggleAutoReply}
|
|
16
|
+
icon={<Icon type="settings" />}
|
|
17
|
+
title={titleText}
|
|
18
|
+
aria-label={titleText}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Button, Form } from 'antd';
|
|
2
|
+
import { Dayjs } from 'dayjs';
|
|
3
|
+
import { customize } from '../../customize';
|
|
4
|
+
import { useLocalizer } from '../../localizer';
|
|
5
|
+
import { AutoReplyPeriodInput } from './AutoReplyPeriodInput';
|
|
6
|
+
import { AutoReplyTextInput } from './AutoReplyTextInput';
|
|
7
|
+
import { useEffect } from 'react';
|
|
8
|
+
|
|
9
|
+
export interface AutoReplyFormValue {
|
|
10
|
+
period: [Dayjs, Dayjs];
|
|
11
|
+
text: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface AutoReplyFormProps {
|
|
15
|
+
value: AutoReplyFormValue;
|
|
16
|
+
onSubmit: (value: AutoReplyFormValue) => void;
|
|
17
|
+
busy?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const AUTO_REPLY_FORM_INITIAL_VALUE: AutoReplyFormValue = {
|
|
21
|
+
period: [] as unknown as [Dayjs, Dayjs],
|
|
22
|
+
text: '',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const AutoReplyForm = customize('AutoReplyForm', (props: AutoReplyFormProps) => {
|
|
26
|
+
const { value, busy = false, onSubmit } = props;
|
|
27
|
+
const localizer = useLocalizer();
|
|
28
|
+
|
|
29
|
+
const [form] = Form.useForm<AutoReplyFormValue>();
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
form.setFieldsValue(value);
|
|
33
|
+
}, [value, form]);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Form<AutoReplyFormValue>
|
|
37
|
+
form={form}
|
|
38
|
+
layout="vertical"
|
|
39
|
+
onFinish={onSubmit}
|
|
40
|
+
disabled={busy}
|
|
41
|
+
initialValues={value}
|
|
42
|
+
>
|
|
43
|
+
<AutoReplyPeriodInput name="period" />
|
|
44
|
+
<AutoReplyTextInput name="text" />
|
|
45
|
+
<Button loading={busy} type="primary" block htmlType="submit">
|
|
46
|
+
{localizer.autoReply.submitBtn()}
|
|
47
|
+
</Button>
|
|
48
|
+
</Form>
|
|
49
|
+
);
|
|
50
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import { useCallback, useMemo } from 'react';
|
|
3
|
+
import { Button } from 'antd';
|
|
4
|
+
import { customize } from '../../customize';
|
|
5
|
+
import { useLocalizer } from '../../localizer';
|
|
6
|
+
import { useChatGroupContext } from '../ChatGroupContext';
|
|
7
|
+
import { Icon } from '../../common/Icon';
|
|
8
|
+
import { AutoReply } from '../../../core';
|
|
9
|
+
import { chatifyApi } from '../../../core';
|
|
10
|
+
import { AUTO_REPLY_FORM_INITIAL_VALUE, AutoReplyForm, AutoReplyFormValue } from './AutoReplyForm';
|
|
11
|
+
|
|
12
|
+
function mapToFormValue(autoReply?: AutoReply | null): AutoReplyFormValue {
|
|
13
|
+
if (!autoReply) {
|
|
14
|
+
return AUTO_REPLY_FORM_INITIAL_VALUE;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
period: [dayjs(autoReply.period.start), dayjs(autoReply.period.end)],
|
|
19
|
+
text: autoReply.text,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function useValue() {
|
|
24
|
+
const { data: me } = chatifyApi.useGeCurrentUserAccountQuery();
|
|
25
|
+
|
|
26
|
+
const value = useMemo<AutoReplyFormValue>(() => {
|
|
27
|
+
return mapToFormValue(me?.autoReply);
|
|
28
|
+
}, [me]);
|
|
29
|
+
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function useAutoReplyActions() {
|
|
34
|
+
const meId = chatifyApi.settings.me();
|
|
35
|
+
const [updateAccount, { isLoading }] = chatifyApi.useUpdateAccountMutation();
|
|
36
|
+
|
|
37
|
+
const onSubmit = useCallback(
|
|
38
|
+
(value: AutoReplyFormValue) =>
|
|
39
|
+
updateAccount({
|
|
40
|
+
id: meId,
|
|
41
|
+
autoReply: {
|
|
42
|
+
hasValue: true,
|
|
43
|
+
value: {
|
|
44
|
+
text: value.text,
|
|
45
|
+
period: {
|
|
46
|
+
start: value.period[0].toISOString(),
|
|
47
|
+
end: value.period[1].toISOString(),
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}).unwrap(),
|
|
52
|
+
[updateAccount, meId],
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const onClear = useCallback(
|
|
56
|
+
() =>
|
|
57
|
+
updateAccount({
|
|
58
|
+
id: meId,
|
|
59
|
+
autoReply: {
|
|
60
|
+
hasValue: true,
|
|
61
|
+
value: null,
|
|
62
|
+
},
|
|
63
|
+
}).unwrap(),
|
|
64
|
+
[updateAccount, meId],
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return [onSubmit, isLoading, onClear] as const;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const AutoReplyPanel = customize('AutoReplyPanel', () => {
|
|
71
|
+
const localizer = useLocalizer();
|
|
72
|
+
const { toggleAutoReply } = useChatGroupContext();
|
|
73
|
+
const value = useValue();
|
|
74
|
+
const [onSubmit, submitting, onClear] = useAutoReplyActions();
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className="wxchtf-auto-reply-panel">
|
|
78
|
+
<Button
|
|
79
|
+
onClick={toggleAutoReply}
|
|
80
|
+
className="wxchtf-auto-reply-panel-close"
|
|
81
|
+
type="link"
|
|
82
|
+
icon={<Icon type="close" />}
|
|
83
|
+
/>
|
|
84
|
+
<div className="wxchtf-auto-reply-panel-header">
|
|
85
|
+
<h3>{localizer.autoReply.title()}</h3>
|
|
86
|
+
<Button type="link" onClick={onClear} disabled={submitting} className="wxchtf-auto-reply-panel-clear">
|
|
87
|
+
{localizer.autoReply.clearBtn()}
|
|
88
|
+
</Button>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<AutoReplyForm value={value} busy={submitting ?? false} onSubmit={onSubmit} />
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { DatePicker, Form } from 'antd';
|
|
2
|
+
import { customize } from '../../customize';
|
|
3
|
+
import { useLocalizer } from '../../localizer';
|
|
4
|
+
|
|
5
|
+
export interface AutoReplyPeriodInputProps {
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const AutoReplyPeriodInput = customize('AutoReplyPeriodInput', (props: AutoReplyPeriodInputProps) => {
|
|
10
|
+
const { name } = props;
|
|
11
|
+
const localizer = useLocalizer();
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Form.Item
|
|
15
|
+
label={localizer.autoReply.period.label()}
|
|
16
|
+
name={name}
|
|
17
|
+
rules={[{ required: true, message: localizer.autoReply.period.required() }]}
|
|
18
|
+
>
|
|
19
|
+
<DatePicker.RangePicker format={localizer.autoReply.period.format()} />
|
|
20
|
+
</Form.Item>
|
|
21
|
+
);
|
|
22
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Form, Input } from 'antd';
|
|
2
|
+
import { customize } from '../../customize';
|
|
3
|
+
import { useLocalizer } from '../../localizer';
|
|
4
|
+
|
|
5
|
+
export interface AutoReplyTextInputProps {
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const AutoReplyTextInput = customize('AutoReplyTextInput', (props: AutoReplyTextInputProps) => {
|
|
10
|
+
const { name } = props;
|
|
11
|
+
const localizer = useLocalizer();
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Form.Item
|
|
15
|
+
label={localizer.autoReply.text.label()}
|
|
16
|
+
name={name}
|
|
17
|
+
rules={[{ required: true, message: localizer.autoReply.text.required() }]}
|
|
18
|
+
>
|
|
19
|
+
<Input.TextArea rows={4} />
|
|
20
|
+
</Form.Item>
|
|
21
|
+
);
|
|
22
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AutoReplyButton } from './AutoReplyButton';
|
|
2
|
+
import { AutoReplyForm } from './AutoReplyForm';
|
|
3
|
+
import { AutoReplyPanel } from './AutoReplyPanel';
|
|
4
|
+
import { AutoReplyPeriodInput } from './AutoReplyPeriodInput';
|
|
5
|
+
import { AutoReplyTextInput } from './AutoReplyTextInput';
|
|
6
|
+
|
|
7
|
+
export * from './AutoReplyButton';
|
|
8
|
+
export * from './AutoReplyForm';
|
|
9
|
+
export * from './AutoReplyPanel';
|
|
10
|
+
export * from './AutoReplyPeriodInput';
|
|
11
|
+
export * from './AutoReplyTextInput';
|
|
12
|
+
|
|
13
|
+
export interface AutoReplyCustomizeValue {
|
|
14
|
+
AutoReplyButton?: typeof AutoReplyButton.Component | null;
|
|
15
|
+
AutoReplyForm?: typeof AutoReplyForm.Component | null;
|
|
16
|
+
AutoReplyPanel?: typeof AutoReplyPanel.Component | null;
|
|
17
|
+
AutoReplyPeriodInput?: typeof AutoReplyPeriodInput.Component | null;
|
|
18
|
+
AutoReplyTextInput?: typeof AutoReplyTextInput.Component | null;
|
|
19
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { PropsWithChildren, useContext, useMemo, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
export interface ChatGroupContext {
|
|
4
|
-
view: 'chat' | 'new-chat' | null;
|
|
4
|
+
view: 'chat' | 'new-chat' | 'auto-reply' | null;
|
|
5
5
|
chatId: string | null;
|
|
6
6
|
showMembers: boolean;
|
|
7
7
|
|
|
@@ -9,6 +9,7 @@ export interface ChatGroupContext {
|
|
|
9
9
|
openChat(chatId: string): void;
|
|
10
10
|
toggleNewChat(): void;
|
|
11
11
|
toggleMembers(): void;
|
|
12
|
+
toggleAutoReply(): void;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const ChatGroupReactContext = React.createContext<ChatGroupContext>(null!);
|
|
@@ -42,6 +43,16 @@ export function ChatGroupContext(props: PropsWithChildren<{}>) {
|
|
|
42
43
|
return { ...prev, view: 'new-chat' };
|
|
43
44
|
}
|
|
44
45
|
}),
|
|
46
|
+
toggleAutoReply: () =>
|
|
47
|
+
setState((prev) => {
|
|
48
|
+
if (prev.view === 'auto-reply' && prev.chatId) {
|
|
49
|
+
return { ...prev, view: 'chat' };
|
|
50
|
+
} else if (prev.view === 'auto-reply' && !prev.chatId) {
|
|
51
|
+
return { ...prev, view: null };
|
|
52
|
+
} else {
|
|
53
|
+
return { ...prev, view: 'auto-reply' };
|
|
54
|
+
}
|
|
55
|
+
}),
|
|
45
56
|
}),
|
|
46
57
|
[state],
|
|
47
58
|
);
|
|
@@ -7,9 +7,11 @@ import { ChatGroupContext, useChatGroupContext } from './ChatGroupContext';
|
|
|
7
7
|
import { chatifyApi } from '../../core';
|
|
8
8
|
import { CustomizeContext } from '../customize';
|
|
9
9
|
import { ChatViewCustomizeValue } from '../Chat';
|
|
10
|
+
import { AutoReplyCustomizeValue } from './AutoReply';
|
|
10
11
|
|
|
11
12
|
export interface ChatGroupCustomizeValue
|
|
12
13
|
extends ChatViewCustomizeValue,
|
|
14
|
+
AutoReplyCustomizeValue,
|
|
13
15
|
CreateChatPanelCustomizeValue,
|
|
14
16
|
ChatListPanelCustomizeValue,
|
|
15
17
|
ChatGroupLayoutCustomizeValue {}
|
|
@@ -16,7 +16,7 @@ interface CheckboxListProps {
|
|
|
16
16
|
|
|
17
17
|
function CheckboxList(props: CheckboxListProps) {
|
|
18
18
|
const { value, onChange } = props;
|
|
19
|
-
const { data: accounts, isFetching } = chatifyApi.useGetAccountListQuery();
|
|
19
|
+
const { data: accounts, isFetching } = chatifyApi.useGetAccountListQuery({});
|
|
20
20
|
const me = chatifyApi.settings.me();
|
|
21
21
|
const dataSource = useMemo(() => accounts?.filter((x) => x.id !== me) ?? [], [accounts, me]);
|
|
22
22
|
|