Skip to content

Partners CRM — UI

Routes

RouteComponentDescription
/partners/crmviews/partners/crm/index.vuePartners CRM entry point; lazy-loaded as a child of /partners

The side panel can be opened directly via query parameters:

/partners/crm?type=partner&id={partnerId}
/partners/crm?type=prospect&id={prospectId}

These parameters are read on mount; if both are present the side panel opens automatically to the correct entity. Tasks and mailing modules use these URLs to link back to a specific partner or prospect from notifications and emails.


Screen Map

/partners/crm
├── Header bar
│   ├── View switcher (Kanban / List / Calendar)
│   ├── "+ Create" button → AddProspect.modal.vue
│   └── Settings gear → opens active view's column/filter settings
├── Kamban.vue          (activeView === 'kanban')
├── ListView.vue        (activeView === 'list')
├── CalendarView.vue    (activeView === 'calendar')
├── Sidepanel.vue       (always mounted, toggled via provide)
├── AddProspect.modal.vue
└── ModalAdministrator.vue

Screens

Index (index.vue)

Entry point. Switches between three view components using v-if / v-else-if, keeping only one mounted at a time. Provides shared state to all child components via Vue's provide / inject.

Provide injections

KeyValueConsumers
$kambanactiveViewRef (computed ref to Kamban, List, or Calendar)Sidepanel — calls reload() after a note is saved
$sidepanelSidepanel refKamban — opens panel on drag; List/Calendar — opens panel on row/event click
$amodalAddProspect refAny child that needs to trigger prospect creation
$modalAdmModalAdministrator refList view partner row action
administratorsArray of admin users (role 20)Sidepanel, ModalAdministrator
mdrAgentsArray of MDR agents (role 10)Sidepanel

Lifecycle: On mount, fetches administrator and MDR agent lists via api.catalog.getAdministrators([20, 10]) and stores them in reactive refs shared through provide.


Kanban (Kamban.vue)

Displays partners and partner prospects as cards organized into columns defined by catalog_follow_up_statuses (source = partner). Each column supports infinite scroll.

Data loading

  • Columns: api.catalog.getFollowUpPartnerCategories()GET /catalog/tours?type=partner
  • Cards: api.partner.getOnGroup(params)GET /partner/grouped
  • KPIs: api.partner.getKpis(params)GET /partner/kpis — displayed as a total referral revenue badge above each column

Drag-and-drop behavior

Powered by vuedraggable. Dropping a card does not PATCH the status immediately. Instead, it invokes onEndCallback, which calls $sidepanel.open(item, { open: 'notes', group: targetColumnId }). This opens the side panel with the target column pre-selected in the note form, requiring the user to confirm the stage change by writing a note.

Settings offcanvas: Column visibility and filter presets saved via useTablePreferences with id crm-partners.

Loading state: Skeleton.vue renders placeholder cards while initial data is fetching.


List (ListView.vue)

Paginated DataTable of all partners and partner prospects. Powered by api.partner.getList()GET /partner/list.

Column configuration: Managed by useTablePreferences with id crm-partners. Default columns and filters defined in table.defaults.js.

Row click: Opens $sidepanel with the clicked entity.

Partner-specific row actions (registered partners only):

ActionPermissionDescription
Activate / Deactivatecrm-partnersToggles partner status via api.partner.updatePartnerStatus()
View clientsNavigates to /partners/{id}/clients
View commissionsNavigates to /partners/{id}/commissions
View retained commissionsNavigates to /partners/{id}/commissions_retained
Assign administratorupdate-partnerOpens ModalAdministrator

Calendar (CalendarView.vue)

Displays scheduled follow-up activities using FullCalendar. Fetches from api.partner.getActivities()GET /partner/activities.

The calendar is a UNION of:

  • Scheduled notes for registered partners (from follow_up_comments with scheduled_date)
  • Scheduled notes for partner prospects (from prospect_follow_up_comments with scheduled_date)

Event click: Opens $sidepanel for the corresponding entity.

Filters: Date range, activity filter (overdue, upcoming, today, month), entity type (partner / prospect), pipeline column, locale. Saved via useTablePreferences with id crm-partners-calendar.


Side Panel (Sidepanel.vue)

Full-screen offcanvas (Offcanvas component with extension: true) that shows detail for the selected partner or partner prospect. Dispatches to the correct API based on options.type.

Layout: Three-column layout within the offcanvas body.

ColumnContents
Left (30%)Contact card (name, id, pipeline badge, email, phone, balance); lead summary table (source badge, company link, created/first contact/last contact dates); Add Reminder button
Center (40%)Active tab content (Notes timeline, Contacts list, Mail tab, Details form)
Right (30%)Activity feed placeholder

Tabs

TabComponentAPI called
Follow-up / NotesFollow/Note.form.vue + notes timelinePOST /partner/{id}/notes or POST /prospects/{id}/notes
ContactsFollow/Contact.form.vuePOST /partner/{id}/contacts or prospect contacts API
MailShared MailingTab componentMailing module (partners / partner_prospects)
DetailsFollow/Details.form.vuePATCH /partner/{id}/data or PATCH /prospects/{id}/partner-data

Source badge: The left column always shows either a "Platform" badge (registered partner) or a "New" badge (partner prospect).

Registered partner link: For type = partner, the ID shown in the header is a router link to /partners/{id}/clients.

Reminder: The "Add Reminder" button shows an inline TodoForm that creates a task linked to the current entity via URL /partners/crm?type={type}&id={id}.

Opening the panel

js
// Programmatically open from any child component
const sidepanel = inject('$sidepanel')
sidepanel.value.open(item, { open: 'notes', group: targetColumnId })

Module-Specific Components

All under frontend/client/src/views/partners/components/crm/:

FileRole
Kamban.vueKanban board with infinite-scroll columns and drag-and-drop
ListView.vueDataTable with partner-specific row actions
CalendarView.vueFullCalendar activity view
Sidepanel.vueThree-column offcanvas detail panel
AddProspect.modal.vueModal to create a new partner prospect
Skeleton.vueKanban loading skeleton (placeholder cards per column)
table.defaults.jsDefault column visibility and filter config for List and Calendar
Follow/Note.form.vueFollow-up note form: status picker, action type, text, optional schedule date
Follow/Details.form.vuePartner metadata form: URL, type, origin, rating, locale, social network
Follow/Contact.form.vueContact CRUD form: name, email, phone code + number, position

Related (shared, not under crm/):

FileRole
views/partners/components/ModalAministrator.vueAssign administrator modal (opened from List view)
components/interface/FollowUp/Notes.vueShared notes timeline renderer
components/interface/FollowUp/Contacts.vueShared contacts list renderer
components/interface/Email/MailingTab.vueShared email tab
views/tasks/components/TodoForm.vueReminder/task creation form

User Flows

Creating a Partner Prospect

Logging a Follow-up Note (from side panel)

Moving a Card via Kanban Drag

Editing Partner Details


Permissions Reference

PermissionScopeEffect in UI
crm-partnersAll CRM featuresWithout this, the Partners CRM route is inaccessible and all CRM API calls return 403
update-partnerList viewEnables the "Assign Administrator" row action for registered partners
view-partnersPartners admin tableControls access to /partners (the operational table), not this CRM
crm-view-allCalendar / ListEnables salesman filter and broader activity visibility

State Management

The Partners CRM uses Vue's provide / inject pattern for cross-component communication rather than a Pinia store. This is intentional — the shared state (open panel, active view ref, modal refs) is ephemeral UI state tied to the lifetime of the index.vue component tree.

Table preferences (column visibility, active filters) are persisted through the useTablePreferences composable with the following IDs:

ViewPreference ID
Kanbancrm-partners
Listcrm-partners
Calendarcrm-partners-calendar

Preferences are stored in both localStorage (for immediate reads) and the API (for cross-device persistence).


i18n Keys

Partners CRM-specific i18n keys are defined in:

frontend/client/src/constants/partnersCrm.i18n.js

This file provides translation keys for CRM column labels specific to the partner channel (e.g., referral counts, verified status). General CRM keys (crm.*) and action/label keys are shared with the main CRM.

Envia Admin