@nextsparkjs/theme-crm 0.1.0-beta.1 → 0.1.0-beta.100
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/LICENSE +21 -0
- package/config/app.config.ts +4 -5
- package/config/dashboard.config.ts +13 -0
- package/config/permissions.config.ts +11 -0
- package/entities/activities/api/docs.md +146 -0
- package/entities/activities/api/presets.ts +132 -0
- package/entities/campaigns/api/docs.md +140 -0
- package/entities/campaigns/api/presets.ts +147 -0
- package/entities/companies/api/docs.md +139 -0
- package/entities/companies/api/presets.ts +107 -0
- package/entities/contacts/api/docs.md +139 -0
- package/entities/contacts/api/presets.ts +98 -0
- package/entities/leads/api/docs.md +132 -0
- package/entities/leads/api/presets.ts +109 -0
- package/entities/notes/api/docs.md +135 -0
- package/entities/notes/api/presets.ts +115 -0
- package/entities/opportunities/api/docs.md +151 -0
- package/entities/opportunities/api/presets.ts +151 -0
- package/entities/pipelines/api/docs.md +145 -0
- package/entities/pipelines/api/presets.ts +118 -0
- package/entities/products/api/docs.md +137 -0
- package/entities/products/api/presets.ts +132 -0
- package/lib/selectors.ts +2 -3
- package/package.json +8 -3
- package/styles/globals.css +37 -1
- package/tests/cypress/e2e/api/activities/activities-crud.cy.ts +686 -0
- package/tests/cypress/e2e/api/campaigns/campaigns-crud.cy.ts +592 -0
- package/tests/cypress/e2e/api/companies/companies-crud.cy.ts +682 -0
- package/tests/cypress/e2e/api/contacts/contacts-crud.cy.ts +668 -0
- package/tests/cypress/e2e/api/leads/leads-crud.cy.ts +648 -0
- package/tests/cypress/e2e/api/notes/notes-crud.cy.ts +424 -0
- package/tests/cypress/e2e/api/opportunities/opportunities-crud.cy.ts +865 -0
- package/tests/cypress/e2e/api/pipelines/pipelines-crud.cy.ts +545 -0
- package/tests/cypress/e2e/api/products/products-crud.cy.ts +447 -0
- package/tests/cypress/e2e/ui/activities/activities-admin.cy.ts +268 -0
- package/tests/cypress/e2e/ui/activities/activities-member.cy.ts +257 -0
- package/tests/cypress/e2e/ui/activities/activities-owner.cy.ts +268 -0
- package/tests/cypress/e2e/ui/companies/companies-admin.cy.ts +188 -0
- package/tests/cypress/e2e/ui/companies/companies-member.cy.ts +166 -0
- package/tests/cypress/e2e/ui/companies/companies-owner.cy.ts +189 -0
- package/tests/cypress/e2e/ui/contacts/contacts-admin.cy.ts +252 -0
- package/tests/cypress/e2e/ui/contacts/contacts-member.cy.ts +224 -0
- package/tests/cypress/e2e/ui/contacts/contacts-owner.cy.ts +236 -0
- package/tests/cypress/e2e/ui/leads/leads-admin.cy.ts +286 -0
- package/tests/cypress/e2e/ui/leads/leads-member.cy.ts +193 -0
- package/tests/cypress/e2e/ui/leads/leads-owner.cy.ts +210 -0
- package/tests/cypress/e2e/ui/opportunities/opportunities-admin.cy.ts +197 -0
- package/tests/cypress/e2e/ui/opportunities/opportunities-member.cy.ts +229 -0
- package/tests/cypress/e2e/ui/opportunities/opportunities-owner.cy.ts +196 -0
- package/tests/cypress/e2e/ui/pipelines/pipelines-admin.cy.ts +320 -0
- package/tests/cypress/e2e/ui/pipelines/pipelines-member.cy.ts +262 -0
- package/tests/cypress/e2e/ui/pipelines/pipelines-owner.cy.ts +282 -0
- package/tests/cypress/fixtures/blocks.json +9 -0
- package/tests/cypress/fixtures/entities.json +240 -0
- package/tests/cypress/src/components/CRMDataTable.js +223 -0
- package/tests/cypress/src/components/CRMMobileNav.js +138 -0
- package/tests/cypress/src/components/CRMSidebar.js +145 -0
- package/tests/cypress/src/components/CRMTopBar.js +194 -0
- package/tests/cypress/src/components/DealCard.js +197 -0
- package/tests/cypress/src/components/EntityDetail.ts +290 -0
- package/tests/cypress/src/components/EntityForm.ts +357 -0
- package/tests/cypress/src/components/EntityList.ts +360 -0
- package/tests/cypress/src/components/PipelineKanban.js +204 -0
- package/tests/cypress/src/components/StageColumn.js +196 -0
- package/tests/cypress/src/components/index.js +13 -0
- package/tests/cypress/src/components/index.ts +22 -0
- package/tests/cypress/src/controllers/ActivityAPIController.ts +113 -0
- package/tests/cypress/src/controllers/BaseAPIController.ts +307 -0
- package/tests/cypress/src/controllers/CampaignAPIController.ts +114 -0
- package/tests/cypress/src/controllers/CompanyAPIController.ts +112 -0
- package/tests/cypress/src/controllers/ContactAPIController.ts +104 -0
- package/tests/cypress/src/controllers/LeadAPIController.ts +96 -0
- package/tests/cypress/src/controllers/NoteAPIController.ts +130 -0
- package/tests/cypress/src/controllers/OpportunityAPIController.ts +134 -0
- package/tests/cypress/src/controllers/PipelineAPIController.ts +116 -0
- package/tests/cypress/src/controllers/ProductAPIController.ts +113 -0
- package/tests/cypress/src/controllers/index.ts +35 -0
- package/tests/cypress/src/entities/ActivitiesPOM.ts +130 -0
- package/tests/cypress/src/entities/CompaniesPOM.ts +117 -0
- package/tests/cypress/src/entities/ContactsPOM.ts +117 -0
- package/tests/cypress/src/entities/LeadsPOM.ts +129 -0
- package/tests/cypress/src/entities/OpportunitiesPOM.ts +178 -0
- package/tests/cypress/src/entities/PipelinesPOM.ts +341 -0
- package/tests/cypress/src/entities/index.ts +31 -0
- package/tests/cypress/src/forms/OpportunityForm.js +316 -0
- package/tests/cypress/src/forms/PipelineForm.js +243 -0
- package/tests/cypress/src/forms/index.js +8 -0
- package/tests/cypress/src/index.js +22 -0
- package/tests/cypress/src/index.ts +68 -0
- package/tests/cypress/src/selectors.ts +50 -0
- package/tests/cypress/src/session-helpers.ts +176 -0
- package/tests/cypress/support/e2e.ts +90 -0
- package/tests/cypress.config.ts +154 -0
- package/tests/jest/__mocks__/jose.js +22 -0
- package/tests/jest/__mocks__/next-server.js +56 -0
- package/tests/jest/jest.config.cjs +131 -0
- package/tests/jest/setup.ts +170 -0
- package/tests/tsconfig.json +15 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Pipelines API
|
|
2
|
+
|
|
3
|
+
Manage sales pipelines with customizable stages. Pipelines define the workflow for tracking opportunities from initial contact to close.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Pipelines API allows you to create, read, update, and delete pipeline configurations. Pipelines contain stages that define the sales process and are used by opportunities to track progress.
|
|
8
|
+
|
|
9
|
+
## Authentication
|
|
10
|
+
|
|
11
|
+
All endpoints require authentication via:
|
|
12
|
+
- **Session cookie** (for browser-based requests)
|
|
13
|
+
- **API Key** header (for server-to-server requests)
|
|
14
|
+
|
|
15
|
+
## Endpoints
|
|
16
|
+
|
|
17
|
+
### List Pipelines
|
|
18
|
+
`GET /api/v1/pipelines`
|
|
19
|
+
|
|
20
|
+
Returns a paginated list of pipelines.
|
|
21
|
+
|
|
22
|
+
**Query Parameters:**
|
|
23
|
+
- `limit` (number, optional): Maximum records to return. Default: 20
|
|
24
|
+
- `offset` (number, optional): Number of records to skip. Default: 0
|
|
25
|
+
- `type` (string, optional): Filter by type (sales, support, project, custom)
|
|
26
|
+
- `isActive` (boolean, optional): Filter by active status
|
|
27
|
+
- `sortBy` (string, optional): Field to sort by
|
|
28
|
+
- `sortOrder` (string, optional): Sort direction (asc, desc)
|
|
29
|
+
|
|
30
|
+
**Example Response:**
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"data": [
|
|
34
|
+
{
|
|
35
|
+
"id": "pipeline_abc123",
|
|
36
|
+
"name": "Sales Pipeline",
|
|
37
|
+
"description": "Main sales process",
|
|
38
|
+
"type": "sales",
|
|
39
|
+
"isDefault": true,
|
|
40
|
+
"isActive": true,
|
|
41
|
+
"stages": [
|
|
42
|
+
{"id": "discovery", "name": "Discovery", "probability": 10, "order": 1},
|
|
43
|
+
{"id": "proposal", "name": "Proposal", "probability": 30, "order": 2},
|
|
44
|
+
{"id": "negotiation", "name": "Negotiation", "probability": 60, "order": 3},
|
|
45
|
+
{"id": "closed", "name": "Closed Won", "probability": 100, "order": 4}
|
|
46
|
+
],
|
|
47
|
+
"dealRottenDays": 30,
|
|
48
|
+
"createdAt": "2024-01-15T10:30:00Z"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"pagination": {
|
|
52
|
+
"total": 3,
|
|
53
|
+
"limit": 20,
|
|
54
|
+
"offset": 0
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Get Single Pipeline
|
|
60
|
+
`GET /api/v1/pipelines/[id]`
|
|
61
|
+
|
|
62
|
+
Returns a single pipeline by ID.
|
|
63
|
+
|
|
64
|
+
### Create Pipeline
|
|
65
|
+
`POST /api/v1/pipelines`
|
|
66
|
+
|
|
67
|
+
Create a new pipeline configuration.
|
|
68
|
+
|
|
69
|
+
**Request Body:**
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"name": "New Sales Pipeline",
|
|
73
|
+
"description": "Custom sales process",
|
|
74
|
+
"type": "sales",
|
|
75
|
+
"isActive": true,
|
|
76
|
+
"stages": [
|
|
77
|
+
{"id": "lead", "name": "Lead", "probability": 5, "order": 1},
|
|
78
|
+
{"id": "qualified", "name": "Qualified", "probability": 25, "order": 2},
|
|
79
|
+
{"id": "demo", "name": "Demo", "probability": 50, "order": 3},
|
|
80
|
+
{"id": "proposal", "name": "Proposal", "probability": 75, "order": 4},
|
|
81
|
+
{"id": "won", "name": "Won", "probability": 100, "order": 5}
|
|
82
|
+
],
|
|
83
|
+
"dealRottenDays": 14
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Update Pipeline
|
|
88
|
+
`PATCH /api/v1/pipelines/[id]`
|
|
89
|
+
|
|
90
|
+
Update an existing pipeline. Supports partial updates.
|
|
91
|
+
|
|
92
|
+
### Delete Pipeline
|
|
93
|
+
`DELETE /api/v1/pipelines/[id]`
|
|
94
|
+
|
|
95
|
+
Delete a pipeline configuration. Note: Cannot delete pipelines with active opportunities.
|
|
96
|
+
|
|
97
|
+
## Fields
|
|
98
|
+
|
|
99
|
+
| Field | Type | Required | Description |
|
|
100
|
+
|-------|------|----------|-------------|
|
|
101
|
+
| name | text | Yes | Pipeline name |
|
|
102
|
+
| description | textarea | No | Pipeline description |
|
|
103
|
+
| type | select | No | Type: sales, support, project, custom |
|
|
104
|
+
| isDefault | boolean | No | Is this the default pipeline |
|
|
105
|
+
| isActive | boolean | No | Is pipeline currently active |
|
|
106
|
+
| stages | json | Yes | Array of stage objects |
|
|
107
|
+
| dealRottenDays | number | No | Days until deal is considered stale |
|
|
108
|
+
| createdAt | datetime | Auto | Creation timestamp |
|
|
109
|
+
| updatedAt | datetime | Auto | Last update timestamp |
|
|
110
|
+
|
|
111
|
+
## Stage Object Structure
|
|
112
|
+
|
|
113
|
+
Each stage in the `stages` array should have:
|
|
114
|
+
|
|
115
|
+
| Property | Type | Description |
|
|
116
|
+
|----------|------|-------------|
|
|
117
|
+
| id | string | Unique stage identifier |
|
|
118
|
+
| name | string | Display name |
|
|
119
|
+
| probability | number | Win probability percentage |
|
|
120
|
+
| order | number | Sort order |
|
|
121
|
+
| color | string | Optional hex color for UI |
|
|
122
|
+
|
|
123
|
+
## Features
|
|
124
|
+
|
|
125
|
+
- **Searchable**: name, description
|
|
126
|
+
- **Sortable**: name, type, isDefault, isActive
|
|
127
|
+
|
|
128
|
+
## Permissions
|
|
129
|
+
|
|
130
|
+
- **Create/Update/Delete**: Owner only
|
|
131
|
+
|
|
132
|
+
## Error Responses
|
|
133
|
+
|
|
134
|
+
| Status | Description |
|
|
135
|
+
|--------|-------------|
|
|
136
|
+
| 400 | Bad Request - Invalid parameters |
|
|
137
|
+
| 401 | Unauthorized - Missing or invalid auth |
|
|
138
|
+
| 403 | Forbidden - Insufficient permissions (owner only) |
|
|
139
|
+
| 404 | Not Found - Pipeline doesn't exist |
|
|
140
|
+
| 409 | Conflict - Cannot delete pipeline with active opportunities |
|
|
141
|
+
| 422 | Validation Error - Invalid data |
|
|
142
|
+
|
|
143
|
+
## Related APIs
|
|
144
|
+
|
|
145
|
+
- **[Opportunities](/api/v1/opportunities)** - Deals using this pipeline
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Presets for Pipelines Entity
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { defineApiEndpoint } from '@nextsparkjs/core/types/api-presets'
|
|
6
|
+
|
|
7
|
+
export default defineApiEndpoint({
|
|
8
|
+
summary: 'Manage sales pipelines with customizable stages',
|
|
9
|
+
presets: [
|
|
10
|
+
{
|
|
11
|
+
id: 'list-all',
|
|
12
|
+
title: 'List All Pipelines',
|
|
13
|
+
description: 'Get all pipelines',
|
|
14
|
+
method: 'GET',
|
|
15
|
+
params: {
|
|
16
|
+
limit: 20
|
|
17
|
+
},
|
|
18
|
+
tags: ['read', 'list']
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 'list-active',
|
|
22
|
+
title: 'List Active Pipelines',
|
|
23
|
+
description: 'Get all active pipelines',
|
|
24
|
+
method: 'GET',
|
|
25
|
+
params: {
|
|
26
|
+
isActive: 'true'
|
|
27
|
+
},
|
|
28
|
+
tags: ['read', 'filter']
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'list-by-type',
|
|
32
|
+
title: 'List by Type',
|
|
33
|
+
description: 'Get pipelines of a specific type',
|
|
34
|
+
method: 'GET',
|
|
35
|
+
params: {
|
|
36
|
+
type: '{{type}}'
|
|
37
|
+
},
|
|
38
|
+
tags: ['read', 'filter']
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'get-default',
|
|
42
|
+
title: 'Get Default Pipeline',
|
|
43
|
+
description: 'Get the default pipeline',
|
|
44
|
+
method: 'GET',
|
|
45
|
+
params: {
|
|
46
|
+
isDefault: 'true'
|
|
47
|
+
},
|
|
48
|
+
tags: ['read', 'filter']
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'create-sales-pipeline',
|
|
52
|
+
title: 'Create Sales Pipeline',
|
|
53
|
+
description: 'Create a new sales pipeline with default stages',
|
|
54
|
+
method: 'POST',
|
|
55
|
+
payload: {
|
|
56
|
+
name: 'Sales Pipeline',
|
|
57
|
+
type: 'sales',
|
|
58
|
+
isActive: true,
|
|
59
|
+
stages: [
|
|
60
|
+
{ id: 'discovery', name: 'Discovery', probability: 10, order: 1 },
|
|
61
|
+
{ id: 'proposal', name: 'Proposal', probability: 30, order: 2 },
|
|
62
|
+
{ id: 'negotiation', name: 'Negotiation', probability: 60, order: 3 },
|
|
63
|
+
{ id: 'won', name: 'Won', probability: 100, order: 4 }
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
tags: ['write', 'create']
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: 'update-stages',
|
|
70
|
+
title: 'Update Stages',
|
|
71
|
+
description: 'Update the stages of a pipeline',
|
|
72
|
+
method: 'PATCH',
|
|
73
|
+
pathParams: {
|
|
74
|
+
id: '{{id}}'
|
|
75
|
+
},
|
|
76
|
+
payload: {
|
|
77
|
+
stages: '{{stages}}'
|
|
78
|
+
},
|
|
79
|
+
tags: ['write', 'update']
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: 'set-default',
|
|
83
|
+
title: 'Set as Default',
|
|
84
|
+
description: 'Set a pipeline as the default',
|
|
85
|
+
method: 'PATCH',
|
|
86
|
+
pathParams: {
|
|
87
|
+
id: '{{id}}'
|
|
88
|
+
},
|
|
89
|
+
payload: {
|
|
90
|
+
isDefault: true
|
|
91
|
+
},
|
|
92
|
+
tags: ['write', 'update']
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'deactivate',
|
|
96
|
+
title: 'Deactivate Pipeline',
|
|
97
|
+
description: 'Deactivate a pipeline',
|
|
98
|
+
method: 'PATCH',
|
|
99
|
+
pathParams: {
|
|
100
|
+
id: '{{id}}'
|
|
101
|
+
},
|
|
102
|
+
payload: {
|
|
103
|
+
isActive: false
|
|
104
|
+
},
|
|
105
|
+
tags: ['write', 'update']
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: 'delete-pipeline',
|
|
109
|
+
title: 'Delete Pipeline',
|
|
110
|
+
description: 'Delete a pipeline',
|
|
111
|
+
method: 'DELETE',
|
|
112
|
+
pathParams: {
|
|
113
|
+
id: '{{id}}'
|
|
114
|
+
},
|
|
115
|
+
tags: ['write', 'delete']
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
})
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Products API
|
|
2
|
+
|
|
3
|
+
Manage products and services catalog. Products can be referenced in opportunities and quotes with pricing, commission rates, and categorization.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Products API allows you to create, read, update, and delete product records. Products represent the items and services your team sells and can be linked to opportunities.
|
|
8
|
+
|
|
9
|
+
## Authentication
|
|
10
|
+
|
|
11
|
+
All endpoints require authentication via:
|
|
12
|
+
- **Session cookie** (for browser-based requests)
|
|
13
|
+
- **API Key** header (for server-to-server requests)
|
|
14
|
+
|
|
15
|
+
## Endpoints
|
|
16
|
+
|
|
17
|
+
### List Products
|
|
18
|
+
`GET /api/v1/products`
|
|
19
|
+
|
|
20
|
+
Returns a paginated list of products.
|
|
21
|
+
|
|
22
|
+
**Query Parameters:**
|
|
23
|
+
- `limit` (number, optional): Maximum records to return. Default: 20
|
|
24
|
+
- `offset` (number, optional): Number of records to skip. Default: 0
|
|
25
|
+
- `type` (string, optional): Filter by type (product, service, subscription, bundle, addon)
|
|
26
|
+
- `isActive` (boolean, optional): Filter by active status
|
|
27
|
+
- `search` (string, optional): Search by code, name, category
|
|
28
|
+
- `sortBy` (string, optional): Field to sort by
|
|
29
|
+
- `sortOrder` (string, optional): Sort direction (asc, desc)
|
|
30
|
+
|
|
31
|
+
**Example Response:**
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"data": [
|
|
35
|
+
{
|
|
36
|
+
"id": "product_abc123",
|
|
37
|
+
"code": "PRD-001",
|
|
38
|
+
"name": "Enterprise License",
|
|
39
|
+
"category": "Software",
|
|
40
|
+
"type": "subscription",
|
|
41
|
+
"description": "Annual enterprise software license",
|
|
42
|
+
"price": 5000,
|
|
43
|
+
"cost": 1000,
|
|
44
|
+
"currency": "USD",
|
|
45
|
+
"unit": "year",
|
|
46
|
+
"isActive": true,
|
|
47
|
+
"commissionRate": 10,
|
|
48
|
+
"createdAt": "2024-01-15T10:30:00Z"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"pagination": {
|
|
52
|
+
"total": 45,
|
|
53
|
+
"limit": 20,
|
|
54
|
+
"offset": 0
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Get Single Product
|
|
60
|
+
`GET /api/v1/products/[id]`
|
|
61
|
+
|
|
62
|
+
Returns a single product by ID.
|
|
63
|
+
|
|
64
|
+
### Create Product
|
|
65
|
+
`POST /api/v1/products`
|
|
66
|
+
|
|
67
|
+
Create a new product record.
|
|
68
|
+
|
|
69
|
+
**Request Body:**
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"code": "SVC-002",
|
|
73
|
+
"name": "Consulting Services",
|
|
74
|
+
"category": "Services",
|
|
75
|
+
"type": "service",
|
|
76
|
+
"description": "Professional consulting services",
|
|
77
|
+
"price": 150,
|
|
78
|
+
"currency": "USD",
|
|
79
|
+
"unit": "hour",
|
|
80
|
+
"isActive": true
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Update Product
|
|
85
|
+
`PATCH /api/v1/products/[id]`
|
|
86
|
+
|
|
87
|
+
Update an existing product. Supports partial updates.
|
|
88
|
+
|
|
89
|
+
### Delete Product
|
|
90
|
+
`DELETE /api/v1/products/[id]`
|
|
91
|
+
|
|
92
|
+
Delete a product record.
|
|
93
|
+
|
|
94
|
+
## Fields
|
|
95
|
+
|
|
96
|
+
| Field | Type | Required | Description |
|
|
97
|
+
|-------|------|----------|-------------|
|
|
98
|
+
| code | text | Yes | Product code or SKU |
|
|
99
|
+
| name | text | Yes | Product name |
|
|
100
|
+
| category | text | No | Product category |
|
|
101
|
+
| type | select | No | Type: product, service, subscription, bundle, addon |
|
|
102
|
+
| description | textarea | No | Product description |
|
|
103
|
+
| price | number | Yes | Standard selling price |
|
|
104
|
+
| cost | number | No | Product cost |
|
|
105
|
+
| currency | select | No | Currency: USD, EUR, GBP, MXN, etc. |
|
|
106
|
+
| unit | select | No | Unit: piece, hour, day, week, month, year, kg, lb, meter, foot, license, user |
|
|
107
|
+
| isActive | boolean | No | Is product currently active |
|
|
108
|
+
| minimumQuantity | number | No | Minimum order quantity |
|
|
109
|
+
| image | url | No | Product image URL |
|
|
110
|
+
| brochureUrl | url | No | Product brochure URL |
|
|
111
|
+
| commissionRate | number | No | Sales commission percentage |
|
|
112
|
+
| createdAt | datetime | Auto | Creation timestamp |
|
|
113
|
+
| updatedAt | datetime | Auto | Last update timestamp |
|
|
114
|
+
|
|
115
|
+
## Features
|
|
116
|
+
|
|
117
|
+
- **Searchable**: code, name, category, description
|
|
118
|
+
- **Sortable**: Most fields
|
|
119
|
+
- **Metadata**: Supported
|
|
120
|
+
|
|
121
|
+
## Permissions
|
|
122
|
+
|
|
123
|
+
- **Create/Update/Delete**: Owner only
|
|
124
|
+
|
|
125
|
+
## Error Responses
|
|
126
|
+
|
|
127
|
+
| Status | Description |
|
|
128
|
+
|--------|-------------|
|
|
129
|
+
| 400 | Bad Request - Invalid parameters |
|
|
130
|
+
| 401 | Unauthorized - Missing or invalid auth |
|
|
131
|
+
| 403 | Forbidden - Insufficient permissions (owner only) |
|
|
132
|
+
| 404 | Not Found - Product doesn't exist |
|
|
133
|
+
| 422 | Validation Error - Invalid data |
|
|
134
|
+
|
|
135
|
+
## Related APIs
|
|
136
|
+
|
|
137
|
+
- **[Opportunities](/api/v1/opportunities)** - Link products to deals
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Presets for Products Entity
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { defineApiEndpoint } from '@nextsparkjs/core/types/api-presets'
|
|
6
|
+
|
|
7
|
+
export default defineApiEndpoint({
|
|
8
|
+
summary: 'Manage products and services catalog',
|
|
9
|
+
presets: [
|
|
10
|
+
{
|
|
11
|
+
id: 'list-all',
|
|
12
|
+
title: 'List All Products',
|
|
13
|
+
description: 'Get all products with pagination',
|
|
14
|
+
method: 'GET',
|
|
15
|
+
params: {
|
|
16
|
+
limit: 20
|
|
17
|
+
},
|
|
18
|
+
tags: ['read', 'list']
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 'list-active',
|
|
22
|
+
title: 'List Active Products',
|
|
23
|
+
description: 'Get all active products',
|
|
24
|
+
method: 'GET',
|
|
25
|
+
params: {
|
|
26
|
+
isActive: 'true'
|
|
27
|
+
},
|
|
28
|
+
tags: ['read', 'filter']
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'list-by-type',
|
|
32
|
+
title: 'List by Type',
|
|
33
|
+
description: 'Get products of a specific type',
|
|
34
|
+
method: 'GET',
|
|
35
|
+
params: {
|
|
36
|
+
type: '{{type}}'
|
|
37
|
+
},
|
|
38
|
+
tags: ['read', 'filter']
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'list-subscriptions',
|
|
42
|
+
title: 'List Subscriptions',
|
|
43
|
+
description: 'Get all subscription products',
|
|
44
|
+
method: 'GET',
|
|
45
|
+
params: {
|
|
46
|
+
type: 'subscription'
|
|
47
|
+
},
|
|
48
|
+
tags: ['read', 'filter']
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'list-services',
|
|
52
|
+
title: 'List Services',
|
|
53
|
+
description: 'Get all service products',
|
|
54
|
+
method: 'GET',
|
|
55
|
+
params: {
|
|
56
|
+
type: 'service'
|
|
57
|
+
},
|
|
58
|
+
tags: ['read', 'filter']
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'search-by-name',
|
|
62
|
+
title: 'Search by Name',
|
|
63
|
+
description: 'Search products by name',
|
|
64
|
+
method: 'GET',
|
|
65
|
+
params: {
|
|
66
|
+
search: '{{name}}'
|
|
67
|
+
},
|
|
68
|
+
tags: ['read', 'search']
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'search-by-code',
|
|
72
|
+
title: 'Search by Code',
|
|
73
|
+
description: 'Search products by code/SKU',
|
|
74
|
+
method: 'GET',
|
|
75
|
+
params: {
|
|
76
|
+
search: '{{code}}'
|
|
77
|
+
},
|
|
78
|
+
tags: ['read', 'search']
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'create-product',
|
|
82
|
+
title: 'Create Product',
|
|
83
|
+
description: 'Create a new product',
|
|
84
|
+
method: 'POST',
|
|
85
|
+
payload: {
|
|
86
|
+
code: 'PRD-NEW',
|
|
87
|
+
name: 'New Product',
|
|
88
|
+
type: 'product',
|
|
89
|
+
price: 100,
|
|
90
|
+
currency: 'USD',
|
|
91
|
+
isActive: true
|
|
92
|
+
},
|
|
93
|
+
tags: ['write', 'create']
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: 'update-price',
|
|
97
|
+
title: 'Update Price',
|
|
98
|
+
description: 'Update product pricing',
|
|
99
|
+
method: 'PATCH',
|
|
100
|
+
pathParams: {
|
|
101
|
+
id: '{{id}}'
|
|
102
|
+
},
|
|
103
|
+
payload: {
|
|
104
|
+
price: '{{newPrice}}'
|
|
105
|
+
},
|
|
106
|
+
tags: ['write', 'update']
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'deactivate',
|
|
110
|
+
title: 'Deactivate Product',
|
|
111
|
+
description: 'Deactivate a product',
|
|
112
|
+
method: 'PATCH',
|
|
113
|
+
pathParams: {
|
|
114
|
+
id: '{{id}}'
|
|
115
|
+
},
|
|
116
|
+
payload: {
|
|
117
|
+
isActive: false
|
|
118
|
+
},
|
|
119
|
+
tags: ['write', 'update']
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: 'delete-product',
|
|
123
|
+
title: 'Delete Product',
|
|
124
|
+
description: 'Delete a product record',
|
|
125
|
+
method: 'DELETE',
|
|
126
|
+
pathParams: {
|
|
127
|
+
id: '{{id}}'
|
|
128
|
+
},
|
|
129
|
+
tags: ['write', 'delete']
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
})
|
package/lib/selectors.ts
CHANGED
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
* - Cypress tests (via tests/cypress/src/selectors.ts)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { createSelectorHelpers } from '@nextsparkjs/core/
|
|
13
|
-
import { CORE_SELECTORS } from '@nextsparkjs/core/lib/test/core-selectors'
|
|
12
|
+
import { createSelectorHelpers, CORE_SELECTORS } from '@nextsparkjs/core/selectors'
|
|
14
13
|
|
|
15
14
|
// =============================================================================
|
|
16
15
|
// BLOCK SELECTORS
|
|
@@ -329,5 +328,5 @@ export type ThemeSelectorsType = typeof THEME_SELECTORS
|
|
|
329
328
|
export type BlockSelectorsType = typeof BLOCK_SELECTORS
|
|
330
329
|
export type EntitySelectorsType = typeof ENTITY_SELECTORS
|
|
331
330
|
export type CRMSelectorsType = typeof CRM_SELECTORS
|
|
332
|
-
export type { Replacements } from '@nextsparkjs/core/
|
|
331
|
+
export type { Replacements } from '@nextsparkjs/core/selectors'
|
|
333
332
|
export { CORE_SELECTORS }
|
package/package.json
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/theme-crm",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.100",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./config/theme.config.ts",
|
|
7
7
|
"requiredPlugins": [],
|
|
8
8
|
"dependencies": {},
|
|
9
9
|
"peerDependencies": {
|
|
10
|
-
"@nextsparkjs/core": "
|
|
10
|
+
"@nextsparkjs/core": "*",
|
|
11
|
+
"@nextsparkjs/testing": "*",
|
|
11
12
|
"lucide-react": "^0.539.0",
|
|
12
13
|
"next": "^15.0.0",
|
|
13
14
|
"next-intl": "^4.0.0",
|
|
14
15
|
"react": "^19.0.0",
|
|
15
16
|
"react-dom": "^19.0.0",
|
|
16
17
|
"zod": "^4.0.0"
|
|
18
|
+
},
|
|
19
|
+
"nextspark": {
|
|
20
|
+
"type": "theme",
|
|
21
|
+
"name": "crm"
|
|
17
22
|
}
|
|
18
|
-
}
|
|
23
|
+
}
|
package/styles/globals.css
CHANGED
|
@@ -5,10 +5,40 @@
|
|
|
5
5
|
* Clean interface with emphasis on data visualization.
|
|
6
6
|
*
|
|
7
7
|
* Design System: Purple/Violet primary, Plus Jakarta Sans typography
|
|
8
|
+
*
|
|
9
|
+
* ÚNICA FUENTE DE VERDAD para estilos del theme.
|
|
10
|
+
* Editar este archivo para customizar el design system.
|
|
8
11
|
*/
|
|
9
12
|
|
|
13
|
+
/* =============================================
|
|
14
|
+
IMPORTS
|
|
15
|
+
============================================= */
|
|
16
|
+
@import "tailwindcss";
|
|
17
|
+
|
|
18
|
+
/* =============================================
|
|
19
|
+
TAILWIND v4 DARK MODE CONFIGURATION
|
|
20
|
+
|
|
21
|
+
Por defecto Tailwind v4 usa @media (prefers-color-scheme: dark)
|
|
22
|
+
para las variantes dark:. Esto causa problemas porque:
|
|
23
|
+
- next-themes usa la clase .dark en el HTML
|
|
24
|
+
- El sistema operativo puede tener dark mode aunque la app use light
|
|
25
|
+
|
|
26
|
+
Esta configuración hace que Tailwind use el selector de clase .dark
|
|
27
|
+
en lugar de la media query, sincronizándose con next-themes.
|
|
28
|
+
============================================= */
|
|
29
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
30
|
+
|
|
31
|
+
@plugin "@tailwindcss/container-queries";
|
|
32
|
+
@import "@nextsparkjs/core/styles/ui.css";
|
|
33
|
+
@import "@nextsparkjs/core/styles/utilities.css";
|
|
34
|
+
@import "@nextsparkjs/core/styles/docs.css";
|
|
35
|
+
@source "../../../**/*.{js,ts,jsx,tsx}";
|
|
36
|
+
/* Core package: monorepo (short path) + npm projects (long path) */
|
|
37
|
+
@source "../node_modules/@nextsparkjs/core/dist/**/*.js";
|
|
38
|
+
@source "../../../../node_modules/@nextsparkjs/core/dist/**/*.js";
|
|
39
|
+
|
|
10
40
|
/* ============================================================================
|
|
11
|
-
|
|
41
|
+
CRM THEME - LIGHT MODE
|
|
12
42
|
============================================================================ */
|
|
13
43
|
|
|
14
44
|
:root {
|
|
@@ -216,7 +246,13 @@
|
|
|
216
246
|
Base Styles
|
|
217
247
|
============================================================================ */
|
|
218
248
|
|
|
249
|
+
* {
|
|
250
|
+
border-color: var(--border);
|
|
251
|
+
}
|
|
252
|
+
|
|
219
253
|
body {
|
|
254
|
+
background-color: var(--background);
|
|
255
|
+
color: var(--foreground);
|
|
220
256
|
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
|
|
221
257
|
}
|
|
222
258
|
|