meta-sovereign 0.51.2 → 0.52.0
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/README.hi.md +7 -7
- package/README.md +7 -7
- package/README.ru.md +7 -7
- package/README.zh.md +1 -1
- package/js/src/web/api-errors.js +3 -0
- package/js/src/web/app-notify.js +2 -0
- package/js/src/web/app.css +82 -0
- package/js/src/web/app.js +14 -8
- package/js/src/web/app.min.js +92 -92
- package/js/src/web/chat-state.js +41 -18
- package/js/src/web/chat-view.js +163 -121
- package/js/src/web/locales/en.js +10 -2
- package/js/src/web/locales/hi.js +8 -1
- package/js/src/web/locales/ru.js +10 -2
- package/js/src/web/locales/zh.js +7 -1
- package/js/src/web/navigation-counts.js +151 -0
- package/js/src/web/operator-model.js +51 -0
- package/js/src/web/operator-view.js +207 -0
- package/js/src/web/shell/app-shell.js +60 -14
- package/js/src/web/shortcuts.js +3 -0
- package/js/src/web/views.js +2 -67
- package/package.json +3 -1
package/README.hi.md
CHANGED
|
@@ -6,13 +6,13 @@ meta-sovereign **किसी व्यक्ति या संगठन क
|
|
|
6
6
|
|
|
7
7
|
### किसके लिए
|
|
8
8
|
|
|
9
|
-
| कौन / क्या | meta-sovereign कैसे मदद करता है
|
|
10
|
-
| --------------------- |
|
|
11
|
-
| **व्यक्ति** | सभी चैट एक जगह, लंबे समय से चुप लोगों से फिर जुड़ना, जो कहा गया वह याद रखना (तथ्य), हर जॉब साइट पर एक जैसा CV।
|
|
12
|
-
| **बिक्री** | हर नेटवर्क के लीड एक CRM में, नियम से ऑडियंस, mass-personal outreach जिसमें हर संदेश एक ही बार और शालीनता से जाता है, फ़ॉलो-अप, तेज़ उत्तर।
|
|
13
|
-
| **मार्केटिंग** | ऑडियंस को broadcast, Telegram चैनल, LinkedIn और X पर पोस्ट, community सदस्य हमेशा ताज़ा, एक opt-out सूची जिसे हर स्वचालित भेजना मानता है।
|
|
14
|
-
| **उपयोगकर्ता सहायता** |
|
|
15
|
-
| **संगठन** | ब्रांड, दुकान या प्रोजेक्ट के लिए वही उपकरण: उसके खाते, उसके संपर्क, उसका डेटा उसकी अपनी मशीन पर। टीम मोड (कई ऑपरेटर) रोडमैप में है।
|
|
9
|
+
| कौन / क्या | meta-sovereign कैसे मदद करता है |
|
|
10
|
+
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| **व्यक्ति** | सभी चैट एक जगह, लंबे समय से चुप लोगों से फिर जुड़ना, जो कहा गया वह याद रखना (तथ्य), हर जॉब साइट पर एक जैसा CV। |
|
|
12
|
+
| **बिक्री** | हर नेटवर्क के लीड एक CRM में, नियम से ऑडियंस, mass-personal outreach जिसमें हर संदेश एक ही बार और शालीनता से जाता है, फ़ॉलो-अप, तेज़ उत्तर। |
|
|
13
|
+
| **मार्केटिंग** | ऑडियंस को broadcast, Telegram चैनल, LinkedIn और X पर पोस्ट, community सदस्य हमेशा ताज़ा, एक opt-out सूची जिसे हर स्वचालित भेजना मानता है। |
|
|
14
|
+
| **उपयोगकर्ता सहायता** | अपठित बातचीत के लिए एक Operator कतार, VK community या Telegram Business खाते से उत्तर, सुरक्षित ड्राफ़्ट के रूप में auto-reply, तथ्यों का ज्ञान-आधार। |
|
|
15
|
+
| **संगठन** | ब्रांड, दुकान या प्रोजेक्ट के लिए वही उपकरण: उसके खाते, उसके संपर्क, उसका डेटा उसकी अपनी मशीन पर। टीम मोड (कई ऑपरेटर) रोडमैप में है। |
|
|
16
16
|
|
|
17
17
|
हर परिदृश्य के लिए आज क्या चलता है, क्या आंशिक है और आगे क्या है — रोडमैप में: [`docs/ROADMAP.hi.md`](docs/ROADMAP.hi.md)।
|
|
18
18
|
|
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ meta-sovereign represents **a person or an organisation online**. Connect Telegr
|
|
|
6
6
|
|
|
7
7
|
### Built for
|
|
8
8
|
|
|
9
|
-
| Who / what | How meta-sovereign helps
|
|
10
|
-
| ----------------- |
|
|
11
|
-
| **Individuals** | All your chats in one place, reconnect with people gone quiet, remember what was said (facts), one CV on every job site.
|
|
12
|
-
| **Sales** | Leads from every network in one CRM, audiences by rule, mass-personal outreach that sends each message once and politely, follow-ups, fast replies.
|
|
13
|
-
| **Marketing** | Broadcasts to audiences, posts to Telegram channels, LinkedIn and X, community members kept fresh, an opt-out list every automated send honours.
|
|
14
|
-
| **User support** | One Operator queue
|
|
15
|
-
| **Organisations** | The same tools for a brand, a shop or a project: its accounts, its contacts, its data on its own machine. Team mode (several operators) is on the roadmap.
|
|
9
|
+
| Who / what | How meta-sovereign helps |
|
|
10
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| **Individuals** | All your chats in one place, reconnect with people gone quiet, remember what was said (facts), one CV on every job site. |
|
|
12
|
+
| **Sales** | Leads from every network in one CRM, audiences by rule, mass-personal outreach that sends each message once and politely, follow-ups, fast replies. |
|
|
13
|
+
| **Marketing** | Broadcasts to audiences, posts to Telegram channels, LinkedIn and X, community members kept fresh, an opt-out list every automated send honours. |
|
|
14
|
+
| **User support** | One Operator queue of unread conversations, answers from a VK community or Telegram Business account, auto-replies as safe drafts, a knowledge base of facts. |
|
|
15
|
+
| **Organisations** | The same tools for a brand, a shop or a project: its accounts, its contacts, its data on its own machine. Team mode (several operators) is on the roadmap. |
|
|
16
16
|
|
|
17
17
|
What works for each scenario today, what is partial and what comes next is in the roadmap: [`docs/ROADMAP.md`](docs/ROADMAP.md).
|
|
18
18
|
|
package/README.ru.md
CHANGED
|
@@ -6,13 +6,13 @@ meta-sovereign представляет **человека или организ
|
|
|
6
6
|
|
|
7
7
|
### Для кого
|
|
8
8
|
|
|
9
|
-
| Кто / что | Чем помогает meta-sovereign
|
|
10
|
-
| --------------- |
|
|
11
|
-
| **Люди** | Все чаты в одном месте, возобновить общение с теми, кто давно молчит, помнить, что было сказано (факты), одно резюме на всех сайтах вакансий.
|
|
12
|
-
| **Продажи** | Лиды из всех сетей в одной CRM, аудитории по правилам, массово-персональные рассылки, где каждое сообщение уходит один раз и вежливо, follow-up, быстрые ответы.
|
|
13
|
-
| **Маркетинг** | Рассылки по аудиториям, посты в каналы Telegram, LinkedIn и X, актуальные участники сообществ, список отписавшихся, который соблюдает каждая автоматическая отправка.
|
|
14
|
-
| **Поддержка** | Одна очередь оператора для
|
|
15
|
-
| **Организации** | Те же инструменты для бренда, магазина или проекта: его аккаунты, его контакты, его данные на его компьютере. Командный режим (несколько операторов) — в дорожной карте.
|
|
9
|
+
| Кто / что | Чем помогает meta-sovereign |
|
|
10
|
+
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| **Люди** | Все чаты в одном месте, возобновить общение с теми, кто давно молчит, помнить, что было сказано (факты), одно резюме на всех сайтах вакансий. |
|
|
12
|
+
| **Продажи** | Лиды из всех сетей в одной CRM, аудитории по правилам, массово-персональные рассылки, где каждое сообщение уходит один раз и вежливо, follow-up, быстрые ответы. |
|
|
13
|
+
| **Маркетинг** | Рассылки по аудиториям, посты в каналы Telegram, LinkedIn и X, актуальные участники сообществ, список отписавшихся, который соблюдает каждая автоматическая отправка. |
|
|
14
|
+
| **Поддержка** | Одна очередь оператора для непрочитанных диалогов, ответы от имени сообщества VK или аккаунта Telegram Business, автоответы как безопасные черновики, база знаний из фактов. |
|
|
15
|
+
| **Организации** | Те же инструменты для бренда, магазина или проекта: его аккаунты, его контакты, его данные на его компьютере. Командный режим (несколько операторов) — в дорожной карте. |
|
|
16
16
|
|
|
17
17
|
Что уже работает для каждого сценария, что частично и что дальше — в дорожной карте: [`docs/ROADMAP.ru.md`](docs/ROADMAP.ru.md).
|
|
18
18
|
|
package/README.zh.md
CHANGED
|
@@ -11,7 +11,7 @@ meta-sovereign 在网上**代表一个人或一个组织**。连接 Telegram、V
|
|
|
11
11
|
| **个人** | 所有聊天集中一处,重新联系久未联系的人,记住说过的话(事实),在每个招聘网站上保持同一份简历。 |
|
|
12
12
|
| **销售** | 来自每个网络的潜在客户汇入一个 CRM,按规则划分受众,大规模个性化外联(每条消息只发一次、礼貌有节奏),跟进,快速回复。 |
|
|
13
13
|
| **市场营销** | 向受众群发,在 Telegram 频道、LinkedIn 和 X 发帖,社区成员保持最新,每次自动发送都遵守退订名单。 |
|
|
14
|
-
| **用户支持** |
|
|
14
|
+
| **用户支持** | 未读会话进入一个 Operator 队列,以 VK 社区或 Telegram Business 账号回复,自动回复以安全草稿形式出现,事实构成知识库。 |
|
|
15
15
|
| **组织** | 同样的工具服务于品牌、店铺或项目:它的账号、它的联系人、它的数据都在它自己的电脑上。团队模式(多名操作员)已列入路线图。 |
|
|
16
16
|
|
|
17
17
|
每个场景今天能用什么、哪些是部分支持、下一步做什么,请见路线图:[`docs/ROADMAP.zh.md`](docs/ROADMAP.zh.md)。
|
package/js/src/web/api-errors.js
CHANGED
|
@@ -34,6 +34,8 @@ export const KNOWN_CODES = [
|
|
|
34
34
|
// Never a toast: a feature probe or a chat that cannot do it is explained
|
|
35
35
|
// inline by the panel that asked. Codes outside KNOWN_CODES are the panels'.
|
|
36
36
|
const INLINE_ONLY = new Set(['unsupported', 'unsupported-chat']);
|
|
37
|
+
// This read-only POST also supplies the background missed-call badge.
|
|
38
|
+
const READ_POSTS = new Set(['/api/telegram/calls']);
|
|
37
39
|
|
|
38
40
|
const seen = new Set();
|
|
39
41
|
|
|
@@ -70,6 +72,7 @@ export const reportApiFailure = ({ path, method = 'GET', status, data }) => {
|
|
|
70
72
|
}
|
|
71
73
|
if (
|
|
72
74
|
method !== 'GET' &&
|
|
75
|
+
!READ_POSTS.has(path) &&
|
|
73
76
|
KNOWN_CODES.includes(failure.code) &&
|
|
74
77
|
!INLINE_ONLY.has(failure.code)
|
|
75
78
|
) {
|
package/js/src/web/app-notify.js
CHANGED
|
@@ -10,6 +10,7 @@ import { useLiveLinks } from './chat-live.js';
|
|
|
10
10
|
import { summarizeChats } from './chat-model.js';
|
|
11
11
|
import { openChat } from './chat-state.js';
|
|
12
12
|
import { useNotifications } from './chat-notify.js';
|
|
13
|
+
import { usePublishChatFeed } from './navigation-counts.js';
|
|
13
14
|
|
|
14
15
|
const NO_CHATS = Object.freeze([]);
|
|
15
16
|
|
|
@@ -21,6 +22,7 @@ export const AppNotifications = ({ api, t, onOpen }) => {
|
|
|
21
22
|
() => (links ? summarizeChats(links) : NO_CHATS),
|
|
22
23
|
[links]
|
|
23
24
|
);
|
|
25
|
+
usePublishChatFeed(chats, links);
|
|
24
26
|
useNotifications({
|
|
25
27
|
chats,
|
|
26
28
|
current: null,
|
package/js/src/web/app.css
CHANGED
|
@@ -12979,3 +12979,85 @@ audio.remote-player {
|
|
|
12979
12979
|
background: #303135;
|
|
12980
12980
|
color: #fff;
|
|
12981
12981
|
}
|
|
12982
|
+
|
|
12983
|
+
/* Operator uses the conversation itself as its queue card. */
|
|
12984
|
+
main[data-view='operator']:has(> .operator-workspace) {
|
|
12985
|
+
max-width: none;
|
|
12986
|
+
padding: 0;
|
|
12987
|
+
}
|
|
12988
|
+
.operator-workspace {
|
|
12989
|
+
height: calc(100dvh - var(--topbar-h));
|
|
12990
|
+
min-height: 0;
|
|
12991
|
+
display: flex;
|
|
12992
|
+
flex-direction: column;
|
|
12993
|
+
gap: 0.75rem;
|
|
12994
|
+
padding: 1rem;
|
|
12995
|
+
}
|
|
12996
|
+
.operator-toolbar {
|
|
12997
|
+
display: flex;
|
|
12998
|
+
align-items: center;
|
|
12999
|
+
justify-content: space-between;
|
|
13000
|
+
gap: 1rem;
|
|
13001
|
+
flex-wrap: wrap;
|
|
13002
|
+
}
|
|
13003
|
+
.operator-toolbar h2,
|
|
13004
|
+
.operator-toolbar p {
|
|
13005
|
+
margin: 0;
|
|
13006
|
+
}
|
|
13007
|
+
.operator-toolbar button {
|
|
13008
|
+
display: inline-flex;
|
|
13009
|
+
align-items: center;
|
|
13010
|
+
gap: 0.4rem;
|
|
13011
|
+
}
|
|
13012
|
+
.operator-card {
|
|
13013
|
+
display: flex;
|
|
13014
|
+
flex: 1;
|
|
13015
|
+
min-height: 0;
|
|
13016
|
+
overflow: hidden;
|
|
13017
|
+
border: 1px solid var(--border);
|
|
13018
|
+
border-radius: 12px;
|
|
13019
|
+
}
|
|
13020
|
+
.chat-shell.chat-embedded {
|
|
13021
|
+
grid-template-columns: minmax(0, 1fr);
|
|
13022
|
+
}
|
|
13023
|
+
.chat-embedded .chat-back {
|
|
13024
|
+
display: none;
|
|
13025
|
+
}
|
|
13026
|
+
.operator-empty {
|
|
13027
|
+
margin: auto;
|
|
13028
|
+
text-align: center;
|
|
13029
|
+
}
|
|
13030
|
+
.nav-icon {
|
|
13031
|
+
position: relative;
|
|
13032
|
+
display: inline-flex;
|
|
13033
|
+
flex-shrink: 0;
|
|
13034
|
+
}
|
|
13035
|
+
.nav-count {
|
|
13036
|
+
position: absolute;
|
|
13037
|
+
top: -0.45rem;
|
|
13038
|
+
right: -0.6rem;
|
|
13039
|
+
min-width: 1.2rem;
|
|
13040
|
+
height: 1.2rem;
|
|
13041
|
+
padding: 0 0.2rem;
|
|
13042
|
+
border: 1px solid var(--bg);
|
|
13043
|
+
border-radius: 999px;
|
|
13044
|
+
background: #111;
|
|
13045
|
+
color: #fff;
|
|
13046
|
+
font-size: 0.65rem;
|
|
13047
|
+
line-height: 1.1rem;
|
|
13048
|
+
text-align: center;
|
|
13049
|
+
font-weight: 700;
|
|
13050
|
+
font-variant-numeric: tabular-nums;
|
|
13051
|
+
}
|
|
13052
|
+
:root[data-theme='dark'] .nav-count {
|
|
13053
|
+
background: #fff;
|
|
13054
|
+
color: #000;
|
|
13055
|
+
}
|
|
13056
|
+
@media (max-width: 640px) {
|
|
13057
|
+
.operator-workspace {
|
|
13058
|
+
height: calc(
|
|
13059
|
+
100dvh - var(--topbar-h) - var(--bottom-nav-h) - var(--safe-bottom)
|
|
13060
|
+
);
|
|
13061
|
+
padding: 0.5rem;
|
|
13062
|
+
}
|
|
13063
|
+
}
|
package/js/src/web/app.js
CHANGED
|
@@ -42,6 +42,7 @@ import { AddthemeHost, useApplyCloudTheme } from './cloud-themes.js';
|
|
|
42
42
|
import { ContactLinkHost } from './contact-links.js';
|
|
43
43
|
import { AppNotifications } from './app-notify.js';
|
|
44
44
|
import { LockScreen, useLocalLock } from './passcode.js';
|
|
45
|
+
import { useNavigationCounts } from './navigation-counts.js';
|
|
45
46
|
|
|
46
47
|
// Browser e2e tests reach the booted api here: in the bundled build the
|
|
47
48
|
// source modules are not each served, so `import('/dom.js')` fails.
|
|
@@ -88,8 +89,14 @@ const useViewportWidth = () => {
|
|
|
88
89
|
return width;
|
|
89
90
|
};
|
|
90
91
|
|
|
92
|
+
const ViewNotifications = ({ active, t, onOpen }) =>
|
|
93
|
+
active === 'chat' || active === 'operator'
|
|
94
|
+
? null
|
|
95
|
+
: el(AppNotifications, { api, t, onOpen });
|
|
96
|
+
|
|
91
97
|
const App = () => {
|
|
92
98
|
const [active, setActive] = useState('chat');
|
|
99
|
+
const counts = useNavigationCounts(api, active);
|
|
93
100
|
const online = useOnlineMode();
|
|
94
101
|
useApplyAppearance();
|
|
95
102
|
// A cloud theme's accent and bubbles on the page (R-Y209).
|
|
@@ -201,6 +208,7 @@ const App = () => {
|
|
|
201
208
|
width,
|
|
202
209
|
active,
|
|
203
210
|
onSelect: setActive,
|
|
211
|
+
counts,
|
|
204
212
|
},
|
|
205
213
|
el(
|
|
206
214
|
'main',
|
|
@@ -236,14 +244,12 @@ const App = () => {
|
|
|
236
244
|
// A t.me/contact or t.me/+phone link opens the person (R-Y217).
|
|
237
245
|
el(ContactLinkHost, { key: 'contact-link-host', api }),
|
|
238
246
|
// The Chat section notifies by itself; the others through this.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
onOpen: () => setActive('chat'),
|
|
246
|
-
}),
|
|
247
|
+
el(ViewNotifications, {
|
|
248
|
+
key: 'notify',
|
|
249
|
+
active,
|
|
250
|
+
t,
|
|
251
|
+
onOpen: () => setActive('chat'),
|
|
252
|
+
}),
|
|
247
253
|
el(TutorialOverlay, {
|
|
248
254
|
key: 'tutorial-overlay',
|
|
249
255
|
open: tutorialOpen,
|