@xuda.io/account_module 1.2.2300 → 1.2.2301

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.
Files changed (2) hide show
  1. package/index.mjs +74 -19
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -55,6 +55,18 @@ const module_path = path.join(process.env.XUDA_HOME, 'cpi') + (!_conf.is_debug ?
55
55
 
56
56
  const db_module = await import(`${module_path}/db_module/index.mjs`);
57
57
 
58
+ // Sort keys for the dashboard list tabs, per docType. Each entry is a fallback
59
+ // chain (first defined value wins) because doc shapes differ. A profile keeps
60
+ // its display name under profile_name, a contact under name. See
61
+ // db_module.find_app_couch_sorted_page.
62
+ const LIST_SORT_PATHS = {
63
+ contact: { created: ['date_created_ts', 'date_created', 'ts'], updated: ['ts', 'date_created_ts'], name: ['name', 'contact_name', 'email'] },
64
+ account_profile: { created: ['date_created_ts', 'date_created', 'ts'], updated: ['ts', 'date_created_ts'], name: ['profile_name', 'name'] },
65
+ };
66
+
67
+ // Dashboard list tabs whose sort preference is remembered per profile.
68
+ const LIST_SORT_TABS = ['ai_chats', 'apps', 'contacts', 'ai_agents', 'account_profiles'];
69
+
58
70
  const ai_ms = await import(`${module_path}/ai_module/index_ms.mjs`);
59
71
  const drive_ms = await import(`${module_path}/drive_module/index_ms.mjs`);
60
72
 
@@ -370,7 +382,7 @@ export const update_account_info = async function (req, job_id, headers) {
370
382
  return save_ret;
371
383
  };
372
384
  export const update_account_preferences = async function (req) {
373
- const { uid, hide_create_button, default_dashboard, sidebar_style, enable_thumbnail_avatar_generation, sidenav_mode, newsletter_opt_in } = req;
385
+ const { uid, hide_create_button, default_dashboard, sidebar_style, enable_thumbnail_avatar_generation, sidenav_mode, newsletter_opt_in, dashboard_sort } = req;
374
386
  try {
375
387
  let account_doc = await db_module.get_couch_doc_native('xuda_accounts', uid);
376
388
  account_doc.ts = Date.now();
@@ -386,6 +398,32 @@ export const update_account_preferences = async function (req) {
386
398
  // flag via router /newsletter/unsubscribe. Only touched when the caller sends it.
387
399
  if (newsletter_opt_in !== undefined) account_doc.preferences.newsletter_opt_in = !!newsletter_opt_in;
388
400
 
401
+ // Dashboard list sort, remembered per PROFILE and per tab so switching
402
+ // profiles brings back that profile's own order:
403
+ // preferences.dashboard_sort[<account_profile_id>][<tab>] = { by, dir }
404
+ // Callers send one tab at a time ({ tab, sort_by, sort_dir, profile_id })
405
+ // and the merge below is surgical, so saving the Contacts order can never
406
+ // drop the one saved for AI Chats or for another profile. Sending
407
+ // sort_by:null clears that tab back to the default order.
408
+ if (dashboard_sort !== undefined) {
409
+ const { tab, sort_by, sort_dir } = dashboard_sort || {};
410
+ if (LIST_SORT_TABS.includes(tab)) {
411
+ const profile_info = await get_active_account_profile_info(uid, dashboard_sort?.profile_id);
412
+ const profile_key = profile_info?.account_profile_id || 'default';
413
+ const all = { ...(account_doc.preferences.dashboard_sort || {}) };
414
+ const for_profile = { ...(all[profile_key] || {}) };
415
+
416
+ if (['date', 'updated', 'name'].includes(sort_by)) {
417
+ for_profile[tab] = { by: sort_by, dir: sort_dir === 'asc' ? 'asc' : 'desc' };
418
+ } else {
419
+ delete for_profile[tab];
420
+ }
421
+
422
+ all[profile_key] = for_profile;
423
+ account_doc.preferences.dashboard_sort = all;
424
+ }
425
+ }
426
+
389
427
  const save_ret = await db_module.save_couch_doc('xuda_accounts', account_doc);
390
428
  if (save_ret.code < 0) {
391
429
  throw new Error(save_ret.data);
@@ -5466,17 +5504,25 @@ export const get_contacts = async function (req, job_id, headers) {
5466
5504
  let contacts = { docs: [], total_docs: 0 };
5467
5505
 
5468
5506
  if (filter_type !== 'pending') {
5469
- contacts = await find_contact_query(account_profile_info.uid, opt);
5470
- if (!limit || contact_id) {
5471
- contacts.total_docs = contacts.docs.length;
5507
+ // User-picked order from the dashboard list controls, see
5508
+ // db_module.find_app_couch_sorted_page. Null when none was asked for,
5509
+ // which leaves the default newest-first path below untouched.
5510
+ const sorted = contact_id ? null : await db_module.find_app_couch_sorted_page(account_profile_info.app_id, opt, req, LIST_SORT_PATHS.contact);
5511
+ if (sorted) {
5512
+ contacts = sorted;
5472
5513
  } else {
5473
- delete opt.sort;
5474
- delete opt.skip;
5475
- opt.limit = 9999;
5476
- opt.fields = ['_id'];
5514
+ contacts = await find_contact_query(account_profile_info.uid, opt);
5515
+ if (!limit || contact_id) {
5516
+ contacts.total_docs = contacts.docs.length;
5517
+ } else {
5518
+ delete opt.sort;
5519
+ delete opt.skip;
5520
+ opt.limit = 9999;
5521
+ opt.fields = ['_id'];
5477
5522
 
5478
- const counter = await find_contact_query(account_profile_info.uid, opt);
5479
- contacts.total_docs = counter.docs.length;
5523
+ const counter = await find_contact_query(account_profile_info.uid, opt);
5524
+ contacts.total_docs = counter.docs.length;
5525
+ }
5480
5526
  }
5481
5527
  }
5482
5528
 
@@ -6157,17 +6203,26 @@ export const get_account_profiles = async function (req) {
6157
6203
  let profiles = { docs: [], total_docs: 0 };
6158
6204
 
6159
6205
  if (filter_type !== 'pending') {
6160
- profiles = await db_module.find_app_couch_query(app_id, opt);
6161
- if (!limit || profile_id) {
6162
- profiles.total_docs = profiles.docs.length;
6206
+ // User-picked order from the dashboard list controls, see
6207
+ // db_module.find_app_couch_sorted_page. Null when none was asked for,
6208
+ // which leaves the default newest-first path below untouched. The main
6209
+ // profile is still floated to the top of the page after enrichment.
6210
+ const sorted = profile_id ? null : await db_module.find_app_couch_sorted_page(app_id, opt, req, LIST_SORT_PATHS.account_profile);
6211
+ if (sorted) {
6212
+ profiles = sorted;
6163
6213
  } else {
6164
- delete opt.sort;
6165
- delete opt.skip;
6166
- opt.limit = 9999;
6167
- opt.fields = ['_id'];
6214
+ profiles = await db_module.find_app_couch_query(app_id, opt);
6215
+ if (!limit || profile_id) {
6216
+ profiles.total_docs = profiles.docs.length;
6217
+ } else {
6218
+ delete opt.sort;
6219
+ delete opt.skip;
6220
+ opt.limit = 9999;
6221
+ opt.fields = ['_id'];
6168
6222
 
6169
- const counter = await db_module.find_app_couch_query(app_id, opt);
6170
- profiles.total_docs = counter.docs.length;
6223
+ const counter = await db_module.find_app_couch_query(app_id, opt);
6224
+ profiles.total_docs = counter.docs.length;
6225
+ }
6171
6226
  }
6172
6227
  }
6173
6228
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xuda.io/account_module",
3
- "version": "1.2.2300",
3
+ "version": "1.2.2301",
4
4
  "description": "Xuda Account Server Module",
5
5
  "main": "index.mjs",
6
6
  "dependencies": {