orbitx-core-models 11.178.0 → 11.180.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.
Files changed (59) hide show
  1. package/dist/activity/recorder.d.ts +2 -2
  2. package/dist/activity/recorder.d.ts.map +1 -1
  3. package/dist/activity/recorder.js +4 -7
  4. package/dist/constants/ticketCategories.d.ts +41 -20
  5. package/dist/constants/ticketCategories.d.ts.map +1 -1
  6. package/dist/constants/ticketCategories.js +212 -53
  7. package/dist/helpers/chatAttachments.d.ts +4 -3
  8. package/dist/helpers/chatAttachments.d.ts.map +1 -1
  9. package/dist/helpers/chatAttachments.js +7 -7
  10. package/dist/helpers/emailTemplates.d.ts.map +1 -1
  11. package/dist/helpers/emailTemplates.js +4 -5
  12. package/dist/helpers/ownTickets.d.ts +3 -1
  13. package/dist/helpers/ownTickets.d.ts.map +1 -1
  14. package/dist/helpers/ownTickets.js +30 -11
  15. package/dist/helpers/privateFiles.d.ts +14 -0
  16. package/dist/helpers/privateFiles.d.ts.map +1 -0
  17. package/dist/helpers/privateFiles.js +45 -0
  18. package/dist/helpers/requestInfo.d.ts +47 -0
  19. package/dist/helpers/requestInfo.d.ts.map +1 -0
  20. package/dist/helpers/requestInfo.js +156 -0
  21. package/dist/helpers/s3Storage.d.ts +24 -2
  22. package/dist/helpers/s3Storage.d.ts.map +1 -1
  23. package/dist/helpers/s3Storage.js +73 -5
  24. package/dist/helpers/sessions.d.ts +51 -3
  25. package/dist/helpers/sessions.d.ts.map +1 -1
  26. package/dist/helpers/sessions.js +144 -11
  27. package/dist/index.d.ts +8 -5
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +16 -2
  30. package/dist/interfaces/company.interface.d.ts +2 -0
  31. package/dist/interfaces/company.interface.d.ts.map +1 -1
  32. package/dist/interfaces/session.interface.d.ts +2 -0
  33. package/dist/interfaces/session.interface.d.ts.map +1 -1
  34. package/dist/interfaces/subscription.interface.d.ts +2 -0
  35. package/dist/interfaces/subscription.interface.d.ts.map +1 -1
  36. package/dist/interfaces/ticket.interface.d.ts +30 -26
  37. package/dist/interfaces/ticket.interface.d.ts.map +1 -1
  38. package/dist/interfaces/ticket.interface.js +28 -4
  39. package/dist/interfaces/user.interface.d.ts +4 -0
  40. package/dist/interfaces/user.interface.d.ts.map +1 -1
  41. package/dist/interfaces/vertical.interface.d.ts +1 -1
  42. package/dist/interfaces/vertical.interface.d.ts.map +1 -1
  43. package/dist/models/company.model.d.ts.map +1 -1
  44. package/dist/models/company.model.js +3 -0
  45. package/dist/models/session.model.d.ts.map +1 -1
  46. package/dist/models/session.model.js +4 -0
  47. package/dist/models/subscription.model.d.ts.map +1 -1
  48. package/dist/models/subscription.model.js +4 -0
  49. package/dist/models/ticket.model.d.ts.map +1 -1
  50. package/dist/models/ticket.model.js +24 -38
  51. package/dist/models/user.model.d.ts.map +1 -1
  52. package/dist/models/user.model.js +7 -0
  53. package/dist/models/vertical.model.js +1 -1
  54. package/dist/routing/ticketRouting.d.ts +11 -1
  55. package/dist/routing/ticketRouting.d.ts.map +1 -1
  56. package/dist/routing/ticketRouting.js +82 -33
  57. package/dist/utils/ticketSanitize.d.ts.map +1 -1
  58. package/dist/utils/ticketSanitize.js +4 -0
  59. package/package.json +1 -1
@@ -1,4 +1,5 @@
1
1
  import { ActivityDashboard, IActivityChange } from "../interfaces/activityLog.interface";
2
+ import { clientIp } from "../helpers/requestInfo";
2
3
  export type ActivityActor = {
3
4
  kind: "ops" | "agent" | "client" | "partner" | "system";
4
5
  id?: unknown;
@@ -72,7 +73,6 @@ export interface ActivityRecorderOptions {
72
73
  ignore?: RegExp[];
73
74
  sessionOf?: (req: Req) => string | undefined;
74
75
  }
75
- export declare function clientIp(req: Req): string | undefined;
76
+ export { clientIp };
76
77
  export declare function activityRecorder(options: ActivityRecorderOptions): (req: Req, res: Res, next: () => void) => void;
77
- export {};
78
78
  //# sourceMappingURL=recorder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/activity/recorder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/activity/recorder.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clientIp = void 0;
3
4
  exports.recordActivity = recordActivity;
4
- exports.clientIp = clientIp;
5
5
  exports.activityRecorder = activityRecorder;
6
6
  const mongoose_1 = require("mongoose");
7
7
  const activityLog_model_1 = require("../models/activityLog.model");
8
+ const requestInfo_1 = require("../helpers/requestInfo");
9
+ Object.defineProperty(exports, "clientIp", { enumerable: true, get: function () { return requestInfo_1.clientIp; } });
8
10
  const asId = (v) => (v && mongoose_1.Types.ObjectId.isValid(String(v)) ? new mongoose_1.Types.ObjectId(String(v)) : undefined);
9
11
  const clip = (v, n) => (v == null ? undefined : String(v).slice(0, n));
10
12
  /** Writes one record. Never throws; a failure is only logged. */
@@ -60,11 +62,6 @@ function humanize(path) {
60
62
  .map((p) => p.replace(/[-_]/g, " "))
61
63
  .join(" › ");
62
64
  }
63
- function clientIp(req) {
64
- var _a, _b, _c;
65
- const fwd = String(((_a = req.headers) === null || _a === void 0 ? void 0 : _a["x-forwarded-for"]) || "").split(",")[0].trim();
66
- return fwd || ((_b = req.headers) === null || _b === void 0 ? void 0 : _b["x-real-ip"]) || ((_c = req.socket) === null || _c === void 0 ? void 0 : _c.remoteAddress) || undefined;
67
- }
68
65
  function activityRecorder(options) {
69
66
  const rules = options.rules.map((r) => ({
70
67
  ...r,
@@ -120,7 +117,7 @@ function activityRecorder(options) {
120
117
  record: (_h = rule === null || rule === void 0 ? void 0 : rule.record) === null || _h === void 0 ? void 0 : _h.call(rule, ctx),
121
118
  outcome,
122
119
  sensitive: !!(rule === null || rule === void 0 ? void 0 : rule.sensitive) || outcome !== "success",
123
- ip: clientIp(req),
120
+ ip: (0, requestInfo_1.clientIp)(req),
124
121
  userAgent: (_j = req.headers) === null || _j === void 0 ? void 0 : _j["user-agent"],
125
122
  sessionId: (_k = options.sessionOf) === null || _k === void 0 ? void 0 : _k.call(options, req),
126
123
  method,
@@ -1,30 +1,43 @@
1
1
  /**
2
- * Single source of truth for the Phase 28 ticket category taxonomy -- imported by the Client and
3
- * Partner ticket-creation forms, both dashboards' ticket controllers (validation), and Ops's
4
- * Group "handles these ticket categories" checkbox list, so all four places stay in sync without
5
- * a real settings-editable admin screen. That screen (add/edit a category without a code
6
- * release) was asked for in the same Phase 28 batch and is deliberately NOT built here -- it's
7
- * its own admin CRUD + cache-invalidation feature across three frontends, left for a dedicated
8
- * pass. This file is the interim single source instead of four separate hardcoded copies.
2
+ * Single source of truth for the ticket category taxonomy -- the Client and Partner New Ticket
3
+ * forms, both backends' validation, Ops's ticket screens and Settings, and the routing engine all
4
+ * read these lists.
9
5
  *
10
- * Old tickets keep whatever legacy category they were filed under (chat-dispute,
11
- * dashboard-technical-issue, payout-issue, referral-issue, review-submission-issue, other) --
12
- * see CLIENT_TICKET_CATEGORIES_LEGACY/PARTNER_TICKET_CATEGORIES_LEGACY in ticket.interface.ts.
13
- * Per the "no remapping" decision, those are shown as Legacy and never migrated.
6
+ * Oct 2 2026 redesign: categories are named by topic, in the requester's own words, and every
7
+ * category says which team handles it (`team`; a sub-category can override it). The routing
8
+ * engine (routing/ticketRouting.ts) sends the ticket to that team:
9
+ * billing -- the Billing Team (Ops logins whose Ticket Team includes Billing)
10
+ * scripting -- the Scripting Team
11
+ * account-manager -- the Company's / Partner's own Account Manager
12
+ * general -- General Support
13
+ * Sub-categories an Ops admin adds from Settings have no team of their own and use their
14
+ * category's.
15
+ *
16
+ * Old tickets keep whatever category they were filed under; those values are listed below as
17
+ * Legacy (shown with "(Legacy)", never offered on a new ticket) per the "no remapping" decision.
14
18
  */
19
+ import type { TicketTeam } from "../interfaces/ticket.interface";
15
20
  export interface TicketSubCategoryOption {
16
21
  value: string;
17
22
  label: string;
23
+ /** Overrides the category's team for this one sub-category. */
24
+ team?: TicketTeam;
18
25
  }
19
26
  export interface TicketCategoryOption {
20
27
  value: string;
21
28
  label: string;
29
+ /** One line shown under the category name on the New Ticket form, in the requester's words. */
30
+ description?: string;
31
+ /** Who handles tickets in this category (a sub-category's own team wins). */
32
+ team?: TicketTeam;
22
33
  /** Shown under the category as its own dropdown when present; omitted categories skip it. */
23
34
  subCategories?: TicketSubCategoryOption[];
24
35
  /** The requester picks their own Chat/Lead ID from their own records (locked, not free text). */
25
36
  requiresChatId?: boolean;
26
- /** The requester picks their own Invoice ID from their own records. */
37
+ /** The requester gives an invoice / transaction reference (stored in the ticket's invoiceId). */
27
38
  requiresInvoiceId?: boolean;
39
+ /** The label of that reference field ("Invoice ID" when unset). */
40
+ referenceLabel?: string;
28
41
  }
29
42
  export declare const CLIENT_TICKET_CATEGORY_OPTIONS: TicketCategoryOption[];
30
43
  export declare const PARTNER_TICKET_CATEGORY_OPTIONS: TicketCategoryOption[];
@@ -33,18 +46,26 @@ export declare const PARTNER_TICKET_CATEGORY_OPTIONS: TicketCategoryOption[];
33
46
  * accept and display these so an old ticket can be looked at, filtered and re-triaged. */
34
47
  export declare const CLIENT_TICKET_CATEGORY_OPTIONS_LEGACY: TicketCategoryOption[];
35
48
  export declare const PARTNER_TICKET_CATEGORY_OPTIONS_LEGACY: TicketCategoryOption[];
36
- /** Every category value that can appear on any ticket, old or new -- what a Group's
37
- * "handles these ticket categories" checkbox list offers, so routing can still target a legacy
38
- * category on an old, not-yet-resolved ticket as well as the new taxonomy. */
49
+ /** Every category value that can appear on any ticket, old or new, each listed once -- what Ops's
50
+ * category filters and a Group's "handles these ticket categories" checkbox list offer. */
39
51
  export declare const ALL_TICKET_CATEGORY_OPTIONS: TicketCategoryOption[];
40
52
  /** Looks a category value up across every list (new + legacy, client + partner) -- for anywhere
41
- * that just needs the label/shape without caring which dashboard it came from. */
53
+ * that just needs the label/shape without caring which dashboard it came from. A value both
54
+ * portals use is defined once, so it reads the same either way. */
42
55
  export declare function findTicketCategoryOption(value?: string | null): TicketCategoryOption | undefined;
56
+ /** The category list (current + legacy) for one owner type. */
57
+ export declare function ticketCategoryOptionsFor(ownerType?: "Company" | "Partner" | null): TicketCategoryOption[];
58
+ /** A category as one owner type sees it (falls back to any list for a value it doesn't have). */
59
+ export declare function findTicketCategoryOptionFor(ownerType: "Company" | "Partner" | null | undefined, value?: string | null): TicketCategoryOption | undefined;
60
+ /**
61
+ * Which team handles a ticket in this category / sub-category: the sub-category's own team, else
62
+ * the category's, else General Support. Undefined only when there is no category yet (an email
63
+ * ticket nobody has categorised).
64
+ */
65
+ export declare function ticketTeamFor(ownerType: "Company" | "Partner" | null | undefined, category?: string | null, subCategory?: string | null): TicketTeam | undefined;
43
66
  /**
44
- * Phase 28's "Category lists kept in settings" admin screen -- the only category values an admin
45
- * is allowed to touch (their own sub-categories only, never the category itself). Every other
46
- * category here (invoice-dispute, failed-withdrawal, failed-transfer -- the requiresInvoiceId
47
- * ones with no subCategories array at all) has no sub-categories to edit in the first place.
67
+ * The "Category lists kept in settings" admin screen -- the categories whose SUB-categories an
68
+ * admin can edit (never the category itself). Every current category that has sub-categories.
48
69
  */
49
70
  export declare const EDITABLE_SUBCATEGORY_KEYS: {
50
71
  ownerType: "Company" | "Partner";
@@ -1 +1 @@
1
- {"version":3,"file":"ticketCategories.d.ts","sourceRoot":"","sources":["../../src/constants/ticketCategories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,6FAA6F;IAC7F,aAAa,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAC1C,iGAAiG;IACjG,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,8BAA8B,EAAE,oBAAoB,EAqChE,CAAC;AAEF,eAAO,MAAM,+BAA+B,EAAE,oBAAoB,EAgCjE,CAAC;AAEF;;0FAE0F;AAC1F,eAAO,MAAM,qCAAqC,EAAE,oBAAoB,EAEvE,CAAC;AAEF,eAAO,MAAM,sCAAsC,EAAE,oBAAoB,EAMxE,CAAC;AAEF;;8EAE8E;AAC9E,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,EAK7D,CAAC;AAOF;kFACkF;AAClF,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,oBAAoB,GAAG,SAAS,CAEhG;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE;IAAE,SAAS,EAAE,SAAS,GAAG,SAAS,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,EAMlG,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,oBAAoB,EAAE,EAChC,SAAS,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,uBAAuB,EAAE,CAAA;CAAE,EAAE,GAC/E,oBAAoB,EAAE,CAOxB"}
1
+ {"version":3,"file":"ticketCategories.d.ts","sourceRoot":"","sources":["../../src/constants/ticketCategories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAEjE,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,+FAA+F;IAC/F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAC1C,iGAAiG;IACjG,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iGAAiG;IACjG,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAoCD,eAAO,MAAM,8BAA8B,EAAE,oBAAoB,EAoGhE,CAAC;AAEF,eAAO,MAAM,+BAA+B,EAAE,oBAAoB,EAwDjE,CAAC;AA6BF;;0FAE0F;AAC1F,eAAO,MAAM,qCAAqC,EAAE,oBAAoB,EAGvE,CAAC;AAEF,eAAO,MAAM,sCAAsC,EAAE,oBAAoB,EAOxE,CAAC;AAEF;2FAC2F;AAC3F,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,EAKc,CAAC;AAO7E;;mEAEmE;AACnE,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,oBAAoB,GAAG,SAAS,CAEhG;AAED,+DAA+D;AAC/D,wBAAgB,wBAAwB,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,GAAG,oBAAoB,EAAE,CAIzG;AAED,iGAAiG;AACjG,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS,EACnD,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACpB,oBAAoB,GAAG,SAAS,CAElC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,UAAU,GAAG,SAAS,CAKxB;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE;IAAE,SAAS,EAAE,SAAS,GAAG,SAAS,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,EASlG,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,oBAAoB,EAAE,EAChC,SAAS,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,uBAAuB,EAAE,CAAA;CAAE,EAAE,GAC/E,oBAAoB,EAAE,CAOxB"}
@@ -1,26 +1,61 @@
1
1
  "use strict";
2
- /**
3
- * Single source of truth for the Phase 28 ticket category taxonomy -- imported by the Client and
4
- * Partner ticket-creation forms, both dashboards' ticket controllers (validation), and Ops's
5
- * Group "handles these ticket categories" checkbox list, so all four places stay in sync without
6
- * a real settings-editable admin screen. That screen (add/edit a category without a code
7
- * release) was asked for in the same Phase 28 batch and is deliberately NOT built here -- it's
8
- * its own admin CRUD + cache-invalidation feature across three frontends, left for a dedicated
9
- * pass. This file is the interim single source instead of four separate hardcoded copies.
10
- *
11
- * Old tickets keep whatever legacy category they were filed under (chat-dispute,
12
- * dashboard-technical-issue, payout-issue, referral-issue, review-submission-issue, other) --
13
- * see CLIENT_TICKET_CATEGORIES_LEGACY/PARTNER_TICKET_CATEGORIES_LEGACY in ticket.interface.ts.
14
- * Per the "no remapping" decision, those are shown as Legacy and never migrated.
15
- */
16
2
  Object.defineProperty(exports, "__esModule", { value: true });
17
3
  exports.EDITABLE_SUBCATEGORY_KEYS = exports.ALL_TICKET_CATEGORY_OPTIONS = exports.PARTNER_TICKET_CATEGORY_OPTIONS_LEGACY = exports.CLIENT_TICKET_CATEGORY_OPTIONS_LEGACY = exports.PARTNER_TICKET_CATEGORY_OPTIONS = exports.CLIENT_TICKET_CATEGORY_OPTIONS = void 0;
18
4
  exports.findTicketCategoryOption = findTicketCategoryOption;
5
+ exports.ticketCategoryOptionsFor = ticketCategoryOptionsFor;
6
+ exports.findTicketCategoryOptionFor = findTicketCategoryOptionFor;
7
+ exports.ticketTeamFor = ticketTeamFor;
19
8
  exports.applySubCategoryOverrides = applySubCategoryOverrides;
9
+ // Categories both portals offer, defined once so a shared value always means the same thing.
10
+ const DASHBOARD_PROBLEM = {
11
+ value: "dashboard",
12
+ label: "Dashboard Problem",
13
+ description: "Something in this dashboard is broken or slow",
14
+ team: "general",
15
+ subCategories: [
16
+ { value: "error", label: "Error or Something Broken" },
17
+ { value: "slow", label: "Slow or Not Loading" },
18
+ { value: "other", label: "Other Dashboard Issue" },
19
+ ],
20
+ };
21
+ const ACCOUNT_AND_LOGIN = {
22
+ value: "account",
23
+ label: "Account & Login",
24
+ description: "Signing in, users, your business details or account security",
25
+ team: "general",
26
+ subCategories: [
27
+ { value: "login", label: "Can't Sign In" },
28
+ { value: "users-permissions", label: "Users & Permissions" },
29
+ { value: "business-details", label: "Business Details" },
30
+ { value: "security", label: "Security / Unauthorized Access" },
31
+ { value: "other", label: "Other Account Question" },
32
+ ],
33
+ };
34
+ const SOMETHING_ELSE = {
35
+ value: "something-else",
36
+ label: "Something Else",
37
+ description: "Anything not listed above",
38
+ team: "general",
39
+ };
20
40
  exports.CLIENT_TICKET_CATEGORY_OPTIONS = [
41
+ {
42
+ value: "leads",
43
+ label: "Leads & Lead Form",
44
+ description: "A lead you didn't get, lead emails, lead details or your lead form",
45
+ team: "account-manager",
46
+ subCategories: [
47
+ { value: "lead-not-received", label: "Lead Not Received" },
48
+ { value: "lead-emails", label: "Lead Emails Not Arriving" },
49
+ { value: "lead-details", label: "Wrong or Missing Lead Details" },
50
+ { value: "lead-form", label: "Lead Form / Lead Fields" },
51
+ { value: "other", label: "Other Lead Question" },
52
+ ],
53
+ },
21
54
  {
22
55
  value: "dispute-billable-lead",
23
- label: "Dispute Billable Lead",
56
+ label: "Dispute a Lead Charge",
57
+ description: "You were charged for a lead that shouldn't count",
58
+ team: "billing",
24
59
  requiresChatId: true,
25
60
  subCategories: [
26
61
  { value: "out-of-service", label: "Out of Service" },
@@ -28,47 +63,144 @@ exports.CLIENT_TICKET_CATEGORY_OPTIONS = [
28
63
  { value: "invalid", label: "Invalid" },
29
64
  ],
30
65
  },
66
+ {
67
+ value: "billing",
68
+ label: "Billing & Payments",
69
+ description: "Payments, your card, your plan, add-ons or receipts",
70
+ team: "billing",
71
+ subCategories: [
72
+ { value: "payment-failed", label: "Payment Failed / Card Issue" },
73
+ { value: "plan-change", label: "Plan Change or Cancellation" },
74
+ { value: "add-ons", label: "Add-ons" },
75
+ { value: "invoice-question", label: "Invoice or Receipt Question" },
76
+ { value: "other", label: "Other Billing Question" },
77
+ ],
78
+ },
31
79
  {
32
80
  value: "invoice-dispute",
33
- label: "Invoice Dispute",
81
+ label: "Dispute an Invoice",
82
+ description: "Something on a specific invoice is wrong",
83
+ team: "billing",
34
84
  requiresInvoiceId: true,
35
85
  },
36
86
  {
37
- value: "technical-support",
38
- label: "Technical Support",
87
+ value: "scripts",
88
+ label: "Scripts & Chat Answers",
89
+ description: "What our agents say to your website visitors",
90
+ team: "scripting",
39
91
  subCategories: [
40
- { value: "login-access", label: "Login / Access" },
41
- { value: "bug-error", label: "Bug / Error" },
42
- { value: "performance", label: "Performance / Slowness" },
43
- { value: "integration", label: "Integration" },
44
- { value: "other", label: "Other" },
92
+ { value: "wrong-answer", label: "Wrong or Outdated Answer" },
93
+ { value: "missing-info", label: "Missing Information" },
94
+ { value: "script-not-followed", label: "Agent Didn't Follow the Script" },
95
+ { value: "templates", label: "Message Templates" },
96
+ { value: "other", label: "Other Script Issue" },
45
97
  ],
46
98
  },
47
99
  {
48
- value: "account-support",
49
- label: "Account Support",
100
+ value: "widget",
101
+ label: "Chat Widget & Website",
102
+ description: "The chat on your website, its look or the exit pop-up",
103
+ team: "general",
50
104
  subCategories: [
51
- { value: "billing-invoice", label: "Billing / Invoice" },
52
- { value: "profile-settings", label: "Profile / Settings" },
53
- { value: "users-permissions", label: "Users & Permissions" },
54
- { value: "other", label: "Other" },
105
+ { value: "widget-not-showing", label: "Widget Not Showing" },
106
+ { value: "widget-looks-wrong", label: "Widget Looks Wrong" },
107
+ { value: "chat-not-working", label: "Chat Not Working Properly" },
108
+ { value: "exit-popup", label: "Exit Pop-up" },
109
+ { value: "other", label: "Other Widget Issue" },
110
+ ],
111
+ },
112
+ {
113
+ value: "call-connect",
114
+ label: "Call Connect & SMS",
115
+ description: "Calls and text messages to your leads",
116
+ team: "account-manager",
117
+ subCategories: [
118
+ { value: "calls-not-connecting", label: "Calls Not Connecting" },
119
+ { value: "sms", label: "Text Messages (SMS)" },
120
+ { value: "settings", label: "Call Connect Settings" },
121
+ { value: "other", label: "Other Call Connect Question" },
55
122
  ],
56
123
  },
124
+ {
125
+ value: "integrations",
126
+ label: "Integrations",
127
+ description: "Your CRM, calendar, retainer signing or Google Analytics",
128
+ team: "general",
129
+ subCategories: [
130
+ { value: "crm", label: "CRM (HubSpot, Salesforce, Zoho)" },
131
+ { value: "calendar", label: "Calendar / Appointments" },
132
+ { value: "retainer", label: "Retainer Signing" },
133
+ { value: "analytics", label: "Google Analytics" },
134
+ { value: "other", label: "Other Integration" },
135
+ ],
136
+ },
137
+ DASHBOARD_PROBLEM,
138
+ ACCOUNT_AND_LOGIN,
139
+ SOMETHING_ELSE,
57
140
  ];
58
141
  exports.PARTNER_TICKET_CATEGORY_OPTIONS = [
142
+ {
143
+ value: "commissions",
144
+ label: "Commissions & Earnings",
145
+ description: "Your commission, wallet, monthly report or Stripe payout account",
146
+ team: "billing",
147
+ subCategories: [
148
+ { value: "commission-missing", label: "Commission Missing" },
149
+ { value: "commission-wrong", label: "Commission Amount Looks Wrong" },
150
+ { value: "monthly-report", label: "Monthly Report Question" },
151
+ { value: "payout-account", label: "Payout Account (Stripe)" },
152
+ { value: "other", label: "Other Earnings Question" },
153
+ ],
154
+ },
59
155
  {
60
156
  value: "failed-withdrawal",
61
157
  label: "Failed Withdrawal",
158
+ description: "Money you withdrew from your wallet didn't arrive",
159
+ team: "billing",
62
160
  requiresInvoiceId: true,
161
+ referenceLabel: "Transaction ID",
63
162
  },
64
163
  {
65
164
  value: "failed-transfer",
66
- label: "Failed Transfer",
165
+ label: "Failed Commission Payment",
166
+ description: "A monthly commission payment failed or was reversed",
167
+ team: "billing",
67
168
  requiresInvoiceId: true,
169
+ referenceLabel: "Reference ID",
170
+ },
171
+ {
172
+ value: "referrals",
173
+ label: "Referrals & Tier",
174
+ description: "A referral that wasn't credited, your referral link or your partner tier",
175
+ team: "account-manager",
176
+ subCategories: [
177
+ { value: "referral-not-credited", label: "Referral Not Credited" },
178
+ { value: "tier", label: "Tier Not Updated" },
179
+ { value: "referral-link", label: "Referral Link" },
180
+ { value: "other", label: "Other Referral Question" },
181
+ ],
68
182
  },
183
+ {
184
+ value: "reviews",
185
+ label: "Reviews",
186
+ description: "Image or video reviews you submitted",
187
+ team: "account-manager",
188
+ subCategories: [
189
+ { value: "submission-problem", label: "Problem Submitting a Review" },
190
+ { value: "review-rejected", label: "Review Rejected" },
191
+ { value: "other", label: "Other Review Question" },
192
+ ],
193
+ },
194
+ DASHBOARD_PROBLEM,
195
+ ACCOUNT_AND_LOGIN,
196
+ SOMETHING_ELSE,
197
+ ];
198
+ // The Phase 28 (Sep 22) categories, retired on Oct 2 -- same lists for both portals.
199
+ const PHASE28_LEGACY = [
69
200
  {
70
201
  value: "technical-support",
71
- label: "Technical Support",
202
+ label: "Technical Support (Legacy)",
203
+ team: "general",
72
204
  subCategories: [
73
205
  { value: "login-access", label: "Login / Access" },
74
206
  { value: "bug-error", label: "Bug / Error" },
@@ -79,9 +211,10 @@ exports.PARTNER_TICKET_CATEGORY_OPTIONS = [
79
211
  },
80
212
  {
81
213
  value: "account-support",
82
- label: "Account Support",
214
+ label: "Account Support (Legacy)",
215
+ team: "general",
83
216
  subCategories: [
84
- { value: "billing-invoice", label: "Billing / Invoice" },
217
+ { value: "billing-invoice", label: "Billing / Invoice", team: "billing" },
85
218
  { value: "profile-settings", label: "Profile / Settings" },
86
219
  { value: "users-permissions", label: "Users & Permissions" },
87
220
  { value: "other", label: "Other" },
@@ -92,46 +225,72 @@ exports.PARTNER_TICKET_CATEGORY_OPTIONS = [
92
225
  * "create a new ticket" form again. Ops's category dropdowns (triage/reassign) still need to
93
226
  * accept and display these so an old ticket can be looked at, filtered and re-triaged. */
94
227
  exports.CLIENT_TICKET_CATEGORY_OPTIONS_LEGACY = [
95
- { value: "chat-dispute", label: "Chat Dispute (Legacy)", requiresChatId: true },
228
+ { value: "chat-dispute", label: "Chat Dispute (Legacy)", team: "billing", requiresChatId: true },
229
+ ...PHASE28_LEGACY,
96
230
  ];
97
231
  exports.PARTNER_TICKET_CATEGORY_OPTIONS_LEGACY = [
98
- { value: "dashboard-technical-issue", label: "Dashboard / Technical Issue (Legacy)" },
99
- { value: "payout-issue", label: "Payout Issue (Legacy)" },
100
- { value: "referral-issue", label: "Referral Issue (Legacy)" },
101
- { value: "review-submission-issue", label: "Review Submission Error (Legacy)" },
102
- { value: "other", label: "Other (Legacy)" },
232
+ { value: "dashboard-technical-issue", label: "Dashboard / Technical Issue (Legacy)", team: "general" },
233
+ { value: "payout-issue", label: "Payout Issue (Legacy)", team: "billing" },
234
+ { value: "referral-issue", label: "Referral Issue (Legacy)", team: "account-manager" },
235
+ { value: "review-submission-issue", label: "Review Submission Error (Legacy)", team: "account-manager" },
236
+ { value: "other", label: "Other (Legacy)", team: "general" },
237
+ ...PHASE28_LEGACY,
103
238
  ];
104
- /** Every category value that can appear on any ticket, old or new -- what a Group's
105
- * "handles these ticket categories" checkbox list offers, so routing can still target a legacy
106
- * category on an old, not-yet-resolved ticket as well as the new taxonomy. */
239
+ /** Every category value that can appear on any ticket, old or new, each listed once -- what Ops's
240
+ * category filters and a Group's "handles these ticket categories" checkbox list offer. */
107
241
  exports.ALL_TICKET_CATEGORY_OPTIONS = [
108
242
  ...exports.CLIENT_TICKET_CATEGORY_OPTIONS,
109
243
  ...exports.PARTNER_TICKET_CATEGORY_OPTIONS,
110
244
  ...exports.CLIENT_TICKET_CATEGORY_OPTIONS_LEGACY,
111
245
  ...exports.PARTNER_TICKET_CATEGORY_OPTIONS_LEGACY,
112
- ];
246
+ ].filter((opt, i, all) => all.findIndex((o) => o.value === opt.value) === i);
113
247
  function findOption(list, value) {
114
248
  if (!value)
115
249
  return undefined;
116
250
  return list.find((o) => o.value === value);
117
251
  }
118
252
  /** Looks a category value up across every list (new + legacy, client + partner) -- for anywhere
119
- * that just needs the label/shape without caring which dashboard it came from. */
253
+ * that just needs the label/shape without caring which dashboard it came from. A value both
254
+ * portals use is defined once, so it reads the same either way. */
120
255
  function findTicketCategoryOption(value) {
121
256
  return findOption(exports.ALL_TICKET_CATEGORY_OPTIONS, value);
122
257
  }
258
+ /** The category list (current + legacy) for one owner type. */
259
+ function ticketCategoryOptionsFor(ownerType) {
260
+ return ownerType === "Partner"
261
+ ? [...exports.PARTNER_TICKET_CATEGORY_OPTIONS, ...exports.PARTNER_TICKET_CATEGORY_OPTIONS_LEGACY]
262
+ : [...exports.CLIENT_TICKET_CATEGORY_OPTIONS, ...exports.CLIENT_TICKET_CATEGORY_OPTIONS_LEGACY];
263
+ }
264
+ /** A category as one owner type sees it (falls back to any list for a value it doesn't have). */
265
+ function findTicketCategoryOptionFor(ownerType, value) {
266
+ return findOption(ticketCategoryOptionsFor(ownerType), value) || findTicketCategoryOption(value);
267
+ }
268
+ /**
269
+ * Which team handles a ticket in this category / sub-category: the sub-category's own team, else
270
+ * the category's, else General Support. Undefined only when there is no category yet (an email
271
+ * ticket nobody has categorised).
272
+ */
273
+ function ticketTeamFor(ownerType, category, subCategory) {
274
+ var _a;
275
+ if (!category)
276
+ return undefined;
277
+ const option = findTicketCategoryOptionFor(ownerType, category);
278
+ const sub = subCategory ? (_a = option === null || option === void 0 ? void 0 : option.subCategories) === null || _a === void 0 ? void 0 : _a.find((s) => s.value === subCategory) : undefined;
279
+ return (sub === null || sub === void 0 ? void 0 : sub.team) || (option === null || option === void 0 ? void 0 : option.team) || "general";
280
+ }
123
281
  /**
124
- * Phase 28's "Category lists kept in settings" admin screen -- the only category values an admin
125
- * is allowed to touch (their own sub-categories only, never the category itself). Every other
126
- * category here (invoice-dispute, failed-withdrawal, failed-transfer -- the requiresInvoiceId
127
- * ones with no subCategories array at all) has no sub-categories to edit in the first place.
282
+ * The "Category lists kept in settings" admin screen -- the categories whose SUB-categories an
283
+ * admin can edit (never the category itself). Every current category that has sub-categories.
128
284
  */
129
285
  exports.EDITABLE_SUBCATEGORY_KEYS = [
130
- { ownerType: "Company", categoryValue: "dispute-billable-lead" },
131
- { ownerType: "Company", categoryValue: "technical-support" },
132
- { ownerType: "Company", categoryValue: "account-support" },
133
- { ownerType: "Partner", categoryValue: "technical-support" },
134
- { ownerType: "Partner", categoryValue: "account-support" },
286
+ ...exports.CLIENT_TICKET_CATEGORY_OPTIONS.filter((o) => o.subCategories).map((o) => ({
287
+ ownerType: "Company",
288
+ categoryValue: o.value,
289
+ })),
290
+ ...exports.PARTNER_TICKET_CATEGORY_OPTIONS.filter((o) => o.subCategories).map((o) => ({
291
+ ownerType: "Partner",
292
+ categoryValue: o.value,
293
+ })),
135
294
  ];
136
295
  /**
137
296
  * Merges DB overrides onto the hardcoded defaults -- replaces just a matching category's
@@ -1,3 +1,4 @@
1
+ import type { SignFile } from "./privateFiles";
1
2
  /**
2
3
  * What a chat carries besides text: the files the visitor shared, and the delivery status of every SMS an agent
3
4
  * sent. Used by the Employee, Ops and Client backends, so all three dashboards show the same thing.
@@ -22,11 +23,11 @@ export interface SmsStatusRow {
22
23
  errorMessage: string | null;
23
24
  preview: string;
24
25
  }
25
- /** Files the visitor shared in the chat, oldest first. */
26
- export declare function getVisitorDocuments(chatId: unknown): Promise<VisitorDocument[]>;
26
+ /** Files the visitor shared in the chat, oldest first. With `signFile`, each link is a signed (private) link. */
27
+ export declare function getVisitorDocuments(chatId: unknown, signFile?: SignFile, seconds?: number): Promise<VisitorDocument[]>;
27
28
  /** Every SMS an agent sent in the chat, oldest first, each with its own running number. */
28
29
  export declare function getSmsStatus(chatId: unknown): Promise<SmsStatusRow[]>;
29
- export declare function getChatAttachments(chatId: unknown): Promise<{
30
+ export declare function getChatAttachments(chatId: unknown, signFile?: SignFile): Promise<{
30
31
  documents: VisitorDocument[];
31
32
  sms: SmsStatusRow[];
32
33
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"chatAttachments.d.ts","sourceRoot":"","sources":["../../src/helpers/chatAttachments.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAGH,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,KAAG,MAQ7C,CAAC;AAWF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,MAAM,EAAE,IAAI,CAAC;IACb,eAAe,EAAE,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,0DAA0D;AAC1D,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAkBrF;AAED,2FAA2F;AAC3F,wBAAsB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAoB3E;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,eAAe,EAAE,CAAC;IAAC,GAAG,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC,CAGxH"}
1
+ {"version":3,"file":"chatAttachments.d.ts","sourceRoot":"","sources":["../../src/helpers/chatAttachments.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;;GAGG;AAGH,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,KAAG,MAQ7C,CAAC;AAWF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,MAAM,EAAE,IAAI,CAAC;IACb,eAAe,EAAE,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,iHAAiH;AACjH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAoB5H;AAED,2FAA2F;AAC3F,wBAAsB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAoB3E;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,eAAe,EAAE,CAAC;IAAC,GAAG,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC,CAG7I"}
@@ -35,8 +35,8 @@ const kindOf = (mediaType, url) => {
35
35
  return "audio";
36
36
  return "file";
37
37
  };
38
- /** Files the visitor shared in the chat, oldest first. */
39
- async function getVisitorDocuments(chatId) {
38
+ /** Files the visitor shared in the chat, oldest first. With `signFile`, each link is a signed (private) link. */
39
+ async function getVisitorDocuments(chatId, signFile, seconds) {
40
40
  const rows = await message_model_1.Message.find({
41
41
  chatId,
42
42
  isDeleted: { $ne: true },
@@ -46,13 +46,13 @@ async function getVisitorDocuments(chatId) {
46
46
  .sort({ createdAt: 1 })
47
47
  .select("mediaUrl mediaType createdAt")
48
48
  .lean();
49
- return rows.map((m) => ({
49
+ return Promise.all(rows.map(async (m) => ({
50
50
  id: String(m._id),
51
- url: m.mediaUrl,
51
+ url: (signFile ? await signFile(m.mediaUrl, seconds) : m.mediaUrl) || m.mediaUrl,
52
52
  name: (0, exports.fileNameFromUrl)(m.mediaUrl),
53
53
  kind: kindOf(m.mediaType, m.mediaUrl),
54
54
  sharedAt: m.createdAt,
55
- }));
55
+ })));
56
56
  }
57
57
  /** Every SMS an agent sent in the chat, oldest first, each with its own running number. */
58
58
  async function getSmsStatus(chatId) {
@@ -75,7 +75,7 @@ async function getSmsStatus(chatId) {
75
75
  preview: String(m.content || "").replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim().slice(0, 120),
76
76
  }));
77
77
  }
78
- async function getChatAttachments(chatId) {
79
- const [documents, sms] = await Promise.all([getVisitorDocuments(chatId), getSmsStatus(chatId)]);
78
+ async function getChatAttachments(chatId, signFile) {
79
+ const [documents, sms] = await Promise.all([getVisitorDocuments(chatId, signFile), getSmsStatus(chatId)]);
80
80
  return { documents, sms };
81
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"emailTemplates.d.ts","sourceRoot":"","sources":["../../src/helpers/emailTemplates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,kEAAkE,uBAAuB,KAAG,MA4H9H,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,GAAG,MAAM,KAAG,MA2I1D,CAAC"}
1
+ {"version":3,"file":"emailTemplates.d.ts","sourceRoot":"","sources":["../../src/helpers/emailTemplates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,kEAAkE,uBAAuB,KAAG,MA4H9H,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,GAAG,MAAM,KAAG,MA0I1D,CAAC"}
@@ -117,11 +117,11 @@ ${noteHtml}${buttonHtml}
117
117
  </p>
118
118
  <a href="https://www.orbitxpro.com" style="color:#FE5E17;text-decoration:none;font-weight:700;font-size:14px;display:block;margin-bottom:6px;${FONT}">www.orbitxpro.com</a>
119
119
  <p style="font-size:12px;color:#999999;margin:0 0 20px 0;${FONT}">
120
- Questions? Email <a href="mailto:support@orbitxpro.com" style="color:#999999;font-weight:700;text-decoration:none;">support@orbitxpro.com</a>
120
+ Questions? Email us at <a href="mailto:support@orbitxpro.com" style="color:#999999;font-weight:700;text-decoration:none;">support@orbitxpro.com</a>.
121
121
  </p>
122
122
  <p style="font-size:11px;color:#999999;line-height:1.6;border-top:1px solid #eeeeee;padding-top:20px;margin:0;${FONT}">
123
123
  This lead was forwarded through ORBITXPRO. To respond, contact the person who forwarded it; replies to this email aren't monitored.<br>
124
- &copy; 2026 ORBITXPRO Inc. | All rights reserved.
124
+ &copy; ${new Date().getFullYear()} ORBITXPRO LLC | All rights reserved.
125
125
  </p>
126
126
  </td>
127
127
  </tr>
@@ -258,11 +258,10 @@ const resetPasswordEmail = (code) => {
258
258
  </div>
259
259
  <a href="https://www.orbitxpro.com" class="website-link">www.orbitxpro.com</a>
260
260
  <div class="support-container">
261
- Didn't request this?
262
- <a href="mailto:support@orbitxpro.com" class="support-link">Contact Customer Support</a>
261
+ Didn't request this? Email us at <a href="mailto:support@orbitxpro.com" class="support-link">support@orbitxpro.com</a>.
263
262
  </div>
264
263
  <div class="compliance-text">
265
- © 2026 ORBITXPRO Inc. | Security Notification <br>
264
+ © ${new Date().getFullYear()} ORBITXPRO LLC | Security Notification <br>
266
265
  <strong>Please do not reply directly to this email.</strong>
267
266
  </div>
268
267
  </div>
@@ -1,8 +1,10 @@
1
- export declare function createOwnTicketsController({ ownerType, categoryOptions, fallbackAuthorName, uploadAttachments, raiseDispute }: {
1
+ import { type SignFile } from "./privateFiles";
2
+ export declare function createOwnTicketsController({ ownerType, categoryOptions, fallbackAuthorName, uploadAttachments, raiseDispute, signFile }: {
2
3
  ownerType: "Company" | "Partner";
3
4
  categoryOptions: any[];
4
5
  fallbackAuthorName: string;
5
6
  uploadAttachments: (files: any[], ownerId: any) => Promise<any[]>;
7
+ signFile?: SignFile;
6
8
  /** Client only: opens the financial dispute behind a lead-dispute ticket. */
7
9
  raiseDispute?: (input: {
8
10
  leadId: any;