diff --git a/backend/README.md b/backend/README.md
index 2ccf948..65e68ba 100644
--- a/backend/README.md
+++ b/backend/README.md
@@ -1,5 +1,5 @@
-#Sales Pipeline CRM - template backend,
+# Coaching SaaS Workspace - template backend
#### Run App on local machine:
@@ -30,10 +30,10 @@
- `psql postgres -U admin`
- Type this command to creating a new database.
- - `postgres=> CREATE DATABASE db_sales_pipeline_crm;`
+ - `postgres=> CREATE DATABASE db_coaching_saas_workspace;`
- Then give that new user privileges to the new database then quit the `psql`.
- - `postgres=> GRANT ALL PRIVILEGES ON DATABASE db_sales_pipeline_crm TO admin;`
+ - `postgres=> GRANT ALL PRIVILEGES ON DATABASE db_coaching_saas_workspace TO admin;`
- `postgres=> \q`
------------
@@ -49,7 +49,7 @@ http://host_name/api-docs
##### Setup database tables or update after schema change
- `yarn db:migrate`
- ##### Seed the initial data (admin accounts, relevant for the first setup):
+ ##### Seed the initial data (admin users, roles, and coaching demo data):
- `yarn db:seed`
##### Start build:
diff --git a/backend/package.json b/backend/package.json
index 8d6ab72..daaec10 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
- "name": "salespipelinecrm",
- "description": "Sales Pipeline CRM - template backend",
+ "name": "coaching-saas-workspace",
+ "description": "Coaching SaaS Workspace - template backend",
"scripts": {
"start": "npm run db:migrate && npm run db:seed && npm run watch",
"lint": "eslint . --ext .js",
diff --git a/backend/src/db/api/accounts.js b/backend/src/db/api/accounts.js
deleted file mode 100644
index b11fb7a..0000000
--- a/backend/src/db/api/accounts.js
+++ /dev/null
@@ -1,701 +0,0 @@
-
-const db = require('../models');
-const FileDBApi = require('./file');
-const crypto = require('crypto');
-const Utils = require('../utils');
-
-
-
-const Sequelize = db.Sequelize;
-const Op = Sequelize.Op;
-
-module.exports = class AccountsDBApi {
-
-
-
- static async create(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const accounts = await db.accounts.create(
- {
- id: data.id || undefined,
-
- name: data.name
- ||
- null
- ,
-
- domain: data.domain
- ||
- null
- ,
-
- industry: data.industry
- ||
- null
- ,
-
- employee_count: data.employee_count
- ||
- null
- ,
-
- annual_revenue: data.annual_revenue
- ||
- null
- ,
-
- phone: data.phone
- ||
- null
- ,
-
- website: data.website
- ||
- null
- ,
-
- address: data.address
- ||
- null
- ,
-
- account_status: data.account_status
- ||
- null
- ,
-
- last_contacted_at: data.last_contacted_at
- ||
- null
- ,
-
- next_follow_up_at: data.next_follow_up_at
- ||
- null
- ,
-
- notes: data.notes
- ||
- null
- ,
-
- importHash: data.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- },
- { transaction },
- );
-
-
- await accounts.setOwner( data.owner || null, {
- transaction,
- });
-
-
-
-
-
-
- return accounts;
- }
-
-
- static async bulkImport(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- // Prepare data - wrapping individual data transformations in a map() method
- const accountsData = data.map((item, index) => ({
- id: item.id || undefined,
-
- name: item.name
- ||
- null
- ,
-
- domain: item.domain
- ||
- null
- ,
-
- industry: item.industry
- ||
- null
- ,
-
- employee_count: item.employee_count
- ||
- null
- ,
-
- annual_revenue: item.annual_revenue
- ||
- null
- ,
-
- phone: item.phone
- ||
- null
- ,
-
- website: item.website
- ||
- null
- ,
-
- address: item.address
- ||
- null
- ,
-
- account_status: item.account_status
- ||
- null
- ,
-
- last_contacted_at: item.last_contacted_at
- ||
- null
- ,
-
- next_follow_up_at: item.next_follow_up_at
- ||
- null
- ,
-
- notes: item.notes
- ||
- null
- ,
-
- importHash: item.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- createdAt: new Date(Date.now() + index * 1000),
- }));
-
- // Bulk create items
- const accounts = await db.accounts.bulkCreate(accountsData, { transaction });
-
- // For each item created, replace relation files
-
-
- return accounts;
- }
-
- static async update(id, data, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
-
- const accounts = await db.accounts.findByPk(id, {}, {transaction});
-
-
-
-
- const updatePayload = {};
-
- if (data.name !== undefined) updatePayload.name = data.name;
-
-
- if (data.domain !== undefined) updatePayload.domain = data.domain;
-
-
- if (data.industry !== undefined) updatePayload.industry = data.industry;
-
-
- if (data.employee_count !== undefined) updatePayload.employee_count = data.employee_count;
-
-
- if (data.annual_revenue !== undefined) updatePayload.annual_revenue = data.annual_revenue;
-
-
- if (data.phone !== undefined) updatePayload.phone = data.phone;
-
-
- if (data.website !== undefined) updatePayload.website = data.website;
-
-
- if (data.address !== undefined) updatePayload.address = data.address;
-
-
- if (data.account_status !== undefined) updatePayload.account_status = data.account_status;
-
-
- if (data.last_contacted_at !== undefined) updatePayload.last_contacted_at = data.last_contacted_at;
-
-
- if (data.next_follow_up_at !== undefined) updatePayload.next_follow_up_at = data.next_follow_up_at;
-
-
- if (data.notes !== undefined) updatePayload.notes = data.notes;
-
-
- updatePayload.updatedById = currentUser.id;
-
- await accounts.update(updatePayload, {transaction});
-
-
-
- if (data.owner !== undefined) {
- await accounts.setOwner(
-
- data.owner,
-
- { transaction }
- );
- }
-
-
-
-
-
-
-
- return accounts;
- }
-
- static async deleteByIds(ids, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const accounts = await db.accounts.findAll({
- where: {
- id: {
- [Op.in]: ids,
- },
- },
- transaction,
- });
-
- await db.sequelize.transaction(async (transaction) => {
- for (const record of accounts) {
- await record.update(
- {deletedBy: currentUser.id},
- {transaction}
- );
- }
- for (const record of accounts) {
- await record.destroy({transaction});
- }
- });
-
-
- return accounts;
- }
-
- static async remove(id, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
- const accounts = await db.accounts.findByPk(id, options);
-
- await accounts.update({
- deletedBy: currentUser.id
- }, {
- transaction,
- });
-
- await accounts.destroy({
- transaction
- });
-
- return accounts;
- }
-
- static async findBy(where, options) {
- const transaction = (options && options.transaction) || undefined;
-
- const accounts = await db.accounts.findOne(
- { where },
- { transaction },
- );
-
- if (!accounts) {
- return accounts;
- }
-
- const output = accounts.get({plain: true});
-
-
-
-
-
-
- output.contacts_account = await accounts.getContacts_account({
- transaction
- });
-
-
-
- output.leads_account = await accounts.getLeads_account({
- transaction
- });
-
-
-
- output.deals_account = await accounts.getDeals_account({
- transaction
- });
-
-
- output.activities_account = await accounts.getActivities_account({
- transaction
- });
-
-
-
- output.owner = await accounts.getOwner({
- transaction
- });
-
-
-
- return output;
- }
-
- static async findAll(
- filter,
- options
- ) {
- const limit = filter.limit || 0;
- let offset = 0;
- let where = {};
- const currentPage = +filter.page;
-
-
-
-
-
- offset = currentPage * limit;
-
- const orderBy = null;
-
- const transaction = (options && options.transaction) || undefined;
-
- let include = [
-
- {
- model: db.users,
- as: 'owner',
-
- where: filter.owner ? {
- [Op.or]: [
- { id: { [Op.in]: filter.owner.split('|').map(term => Utils.uuid(term)) } },
- {
- firstName: {
- [Op.or]: filter.owner.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
-
-
- ];
-
- if (filter) {
- if (filter.id) {
- where = {
- ...where,
- ['id']: Utils.uuid(filter.id),
- };
- }
-
-
- if (filter.name) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'accounts',
- 'name',
- filter.name,
- ),
- };
- }
-
- if (filter.domain) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'accounts',
- 'domain',
- filter.domain,
- ),
- };
- }
-
- if (filter.industry) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'accounts',
- 'industry',
- filter.industry,
- ),
- };
- }
-
- if (filter.phone) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'accounts',
- 'phone',
- filter.phone,
- ),
- };
- }
-
- if (filter.website) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'accounts',
- 'website',
- filter.website,
- ),
- };
- }
-
- if (filter.address) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'accounts',
- 'address',
- filter.address,
- ),
- };
- }
-
- if (filter.notes) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'accounts',
- 'notes',
- filter.notes,
- ),
- };
- }
-
-
-
-
-
-
- if (filter.employee_countRange) {
- const [start, end] = filter.employee_countRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- employee_count: {
- ...where.employee_count,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- employee_count: {
- ...where.employee_count,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.annual_revenueRange) {
- const [start, end] = filter.annual_revenueRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- annual_revenue: {
- ...where.annual_revenue,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- annual_revenue: {
- ...where.annual_revenue,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.last_contacted_atRange) {
- const [start, end] = filter.last_contacted_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- last_contacted_at: {
- ...where.last_contacted_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- last_contacted_at: {
- ...where.last_contacted_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.next_follow_up_atRange) {
- const [start, end] = filter.next_follow_up_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- next_follow_up_at: {
- ...where.next_follow_up_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- next_follow_up_at: {
- ...where.next_follow_up_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
-
- if (filter.active !== undefined) {
- where = {
- ...where,
- active: filter.active === true || filter.active === 'true'
- };
- }
-
-
- if (filter.account_status) {
- where = {
- ...where,
- account_status: filter.account_status,
- };
- }
-
-
-
-
-
-
-
- if (filter.createdAtRange) {
- const [start, end] = filter.createdAtRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.lte]: end,
- },
- };
- }
- }
- }
-
-
-
-
- const queryOptions = {
- where,
- include,
- distinct: true,
- order: filter.field && filter.sort
- ? [[filter.field, filter.sort]]
- : [['createdAt', 'desc']],
- transaction: options?.transaction,
- logging: console.log
- };
-
- if (!options?.countOnly) {
- queryOptions.limit = limit ? Number(limit) : undefined;
- queryOptions.offset = offset ? Number(offset) : undefined;
- }
-
- try {
- const { rows, count } = await db.accounts.findAndCountAll(queryOptions);
-
- return {
- rows: options?.countOnly ? [] : rows,
- count: count
- };
- } catch (error) {
- console.error('Error executing query:', error);
- throw error;
- }
- }
-
- static async findAllAutocomplete(query, limit, offset, ) {
- let where = {};
-
-
-
- if (query) {
- where = {
- [Op.or]: [
- { ['id']: Utils.uuid(query) },
- Utils.ilike(
- 'accounts',
- 'name',
- query,
- ),
- ],
- };
- }
-
- const records = await db.accounts.findAll({
- attributes: [ 'id', 'name' ],
- where,
- limit: limit ? Number(limit) : undefined,
- offset: offset ? Number(offset) : undefined,
- orderBy: [['name', 'ASC']],
- });
-
- return records.map((record) => ({
- id: record.id,
- label: record.name,
- }));
- }
-
-
-};
-
diff --git a/backend/src/db/api/activities.js b/backend/src/db/api/activities.js
deleted file mode 100644
index f745090..0000000
--- a/backend/src/db/api/activities.js
+++ /dev/null
@@ -1,776 +0,0 @@
-
-const db = require('../models');
-const FileDBApi = require('./file');
-const crypto = require('crypto');
-const Utils = require('../utils');
-
-
-
-const Sequelize = db.Sequelize;
-const Op = Sequelize.Op;
-
-module.exports = class ActivitiesDBApi {
-
-
-
- static async create(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const activities = await db.activities.create(
- {
- id: data.id || undefined,
-
- activity_type: data.activity_type
- ||
- null
- ,
-
- subject: data.subject
- ||
- null
- ,
-
- details: data.details
- ||
- null
- ,
-
- activity_at: data.activity_at
- ||
- null
- ,
-
- due_at: data.due_at
- ||
- null
- ,
-
- completed_at: data.completed_at
- ||
- null
- ,
-
- status: data.status
- ||
- null
- ,
-
- priority: data.priority
- ||
- null
- ,
-
- importHash: data.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- },
- { transaction },
- );
-
-
- await activities.setOwner( data.owner || null, {
- transaction,
- });
-
- await activities.setLead( data.lead || null, {
- transaction,
- });
-
- await activities.setDeal( data.deal || null, {
- transaction,
- });
-
- await activities.setContact( data.contact || null, {
- transaction,
- });
-
- await activities.setAccount( data.account || null, {
- transaction,
- });
-
-
-
-
-
- await FileDBApi.replaceRelationFiles(
- {
- belongsTo: db.activities.getTableName(),
- belongsToColumn: 'attachments',
- belongsToId: activities.id,
- },
- data.attachments,
- options,
- );
-
-
- return activities;
- }
-
-
- static async bulkImport(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- // Prepare data - wrapping individual data transformations in a map() method
- const activitiesData = data.map((item, index) => ({
- id: item.id || undefined,
-
- activity_type: item.activity_type
- ||
- null
- ,
-
- subject: item.subject
- ||
- null
- ,
-
- details: item.details
- ||
- null
- ,
-
- activity_at: item.activity_at
- ||
- null
- ,
-
- due_at: item.due_at
- ||
- null
- ,
-
- completed_at: item.completed_at
- ||
- null
- ,
-
- status: item.status
- ||
- null
- ,
-
- priority: item.priority
- ||
- null
- ,
-
- importHash: item.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- createdAt: new Date(Date.now() + index * 1000),
- }));
-
- // Bulk create items
- const activities = await db.activities.bulkCreate(activitiesData, { transaction });
-
- // For each item created, replace relation files
-
- for (let i = 0; i < activities.length; i++) {
- await FileDBApi.replaceRelationFiles(
- {
- belongsTo: db.activities.getTableName(),
- belongsToColumn: 'attachments',
- belongsToId: activities[i].id,
- },
- data[i].attachments,
- options,
- );
- }
-
-
- return activities;
- }
-
- static async update(id, data, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
-
- const activities = await db.activities.findByPk(id, {}, {transaction});
-
-
-
-
- const updatePayload = {};
-
- if (data.activity_type !== undefined) updatePayload.activity_type = data.activity_type;
-
-
- if (data.subject !== undefined) updatePayload.subject = data.subject;
-
-
- if (data.details !== undefined) updatePayload.details = data.details;
-
-
- if (data.activity_at !== undefined) updatePayload.activity_at = data.activity_at;
-
-
- if (data.due_at !== undefined) updatePayload.due_at = data.due_at;
-
-
- if (data.completed_at !== undefined) updatePayload.completed_at = data.completed_at;
-
-
- if (data.status !== undefined) updatePayload.status = data.status;
-
-
- if (data.priority !== undefined) updatePayload.priority = data.priority;
-
-
- updatePayload.updatedById = currentUser.id;
-
- await activities.update(updatePayload, {transaction});
-
-
-
- if (data.owner !== undefined) {
- await activities.setOwner(
-
- data.owner,
-
- { transaction }
- );
- }
-
- if (data.lead !== undefined) {
- await activities.setLead(
-
- data.lead,
-
- { transaction }
- );
- }
-
- if (data.deal !== undefined) {
- await activities.setDeal(
-
- data.deal,
-
- { transaction }
- );
- }
-
- if (data.contact !== undefined) {
- await activities.setContact(
-
- data.contact,
-
- { transaction }
- );
- }
-
- if (data.account !== undefined) {
- await activities.setAccount(
-
- data.account,
-
- { transaction }
- );
- }
-
-
-
-
-
-
- await FileDBApi.replaceRelationFiles(
- {
- belongsTo: db.activities.getTableName(),
- belongsToColumn: 'attachments',
- belongsToId: activities.id,
- },
- data.attachments,
- options,
- );
-
-
- return activities;
- }
-
- static async deleteByIds(ids, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const activities = await db.activities.findAll({
- where: {
- id: {
- [Op.in]: ids,
- },
- },
- transaction,
- });
-
- await db.sequelize.transaction(async (transaction) => {
- for (const record of activities) {
- await record.update(
- {deletedBy: currentUser.id},
- {transaction}
- );
- }
- for (const record of activities) {
- await record.destroy({transaction});
- }
- });
-
-
- return activities;
- }
-
- static async remove(id, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
- const activities = await db.activities.findByPk(id, options);
-
- await activities.update({
- deletedBy: currentUser.id
- }, {
- transaction,
- });
-
- await activities.destroy({
- transaction
- });
-
- return activities;
- }
-
- static async findBy(where, options) {
- const transaction = (options && options.transaction) || undefined;
-
- const activities = await db.activities.findOne(
- { where },
- { transaction },
- );
-
- if (!activities) {
- return activities;
- }
-
- const output = activities.get({plain: true});
-
-
-
-
-
-
-
-
-
-
-
-
-
- output.owner = await activities.getOwner({
- transaction
- });
-
-
- output.lead = await activities.getLead({
- transaction
- });
-
-
- output.deal = await activities.getDeal({
- transaction
- });
-
-
- output.contact = await activities.getContact({
- transaction
- });
-
-
- output.account = await activities.getAccount({
- transaction
- });
-
-
- output.attachments = await activities.getAttachments({
- transaction
- });
-
-
-
- return output;
- }
-
- static async findAll(
- filter,
- options
- ) {
- const limit = filter.limit || 0;
- let offset = 0;
- let where = {};
- const currentPage = +filter.page;
-
-
-
-
-
- offset = currentPage * limit;
-
- const orderBy = null;
-
- const transaction = (options && options.transaction) || undefined;
-
- let include = [
-
- {
- model: db.users,
- as: 'owner',
-
- where: filter.owner ? {
- [Op.or]: [
- { id: { [Op.in]: filter.owner.split('|').map(term => Utils.uuid(term)) } },
- {
- firstName: {
- [Op.or]: filter.owner.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.leads,
- as: 'lead',
-
- where: filter.lead ? {
- [Op.or]: [
- { id: { [Op.in]: filter.lead.split('|').map(term => Utils.uuid(term)) } },
- {
- lead_name: {
- [Op.or]: filter.lead.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.deals,
- as: 'deal',
-
- where: filter.deal ? {
- [Op.or]: [
- { id: { [Op.in]: filter.deal.split('|').map(term => Utils.uuid(term)) } },
- {
- name: {
- [Op.or]: filter.deal.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.contacts,
- as: 'contact',
-
- where: filter.contact ? {
- [Op.or]: [
- { id: { [Op.in]: filter.contact.split('|').map(term => Utils.uuid(term)) } },
- {
- full_name: {
- [Op.or]: filter.contact.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.accounts,
- as: 'account',
-
- where: filter.account ? {
- [Op.or]: [
- { id: { [Op.in]: filter.account.split('|').map(term => Utils.uuid(term)) } },
- {
- name: {
- [Op.or]: filter.account.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
-
-
- {
- model: db.file,
- as: 'attachments',
- },
-
- ];
-
- if (filter) {
- if (filter.id) {
- where = {
- ...where,
- ['id']: Utils.uuid(filter.id),
- };
- }
-
-
- if (filter.subject) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'activities',
- 'subject',
- filter.subject,
- ),
- };
- }
-
- if (filter.details) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'activities',
- 'details',
- filter.details,
- ),
- };
- }
-
-
-
-
- if (filter.calendarStart && filter.calendarEnd) {
- where = {
- ...where,
- [Op.or]: [
- {
- due_at: {
- [Op.between]: [filter.calendarStart, filter.calendarEnd],
- },
- },
- {
- completed_at: {
- [Op.between]: [filter.calendarStart, filter.calendarEnd],
- },
- },
- ],
- };
- }
-
-
-
- if (filter.activity_atRange) {
- const [start, end] = filter.activity_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- activity_at: {
- ...where.activity_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- activity_at: {
- ...where.activity_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.due_atRange) {
- const [start, end] = filter.due_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- due_at: {
- ...where.due_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- due_at: {
- ...where.due_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.completed_atRange) {
- const [start, end] = filter.completed_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- completed_at: {
- ...where.completed_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- completed_at: {
- ...where.completed_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
-
- if (filter.active !== undefined) {
- where = {
- ...where,
- active: filter.active === true || filter.active === 'true'
- };
- }
-
-
- if (filter.activity_type) {
- where = {
- ...where,
- activity_type: filter.activity_type,
- };
- }
-
- if (filter.status) {
- where = {
- ...where,
- status: filter.status,
- };
- }
-
- if (filter.priority) {
- where = {
- ...where,
- priority: filter.priority,
- };
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (filter.createdAtRange) {
- const [start, end] = filter.createdAtRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.lte]: end,
- },
- };
- }
- }
- }
-
-
-
-
- const queryOptions = {
- where,
- include,
- distinct: true,
- order: filter.field && filter.sort
- ? [[filter.field, filter.sort]]
- : [['createdAt', 'desc']],
- transaction: options?.transaction,
- logging: console.log
- };
-
- if (!options?.countOnly) {
- queryOptions.limit = limit ? Number(limit) : undefined;
- queryOptions.offset = offset ? Number(offset) : undefined;
- }
-
- try {
- const { rows, count } = await db.activities.findAndCountAll(queryOptions);
-
- return {
- rows: options?.countOnly ? [] : rows,
- count: count
- };
- } catch (error) {
- console.error('Error executing query:', error);
- throw error;
- }
- }
-
- static async findAllAutocomplete(query, limit, offset, ) {
- let where = {};
-
-
-
- if (query) {
- where = {
- [Op.or]: [
- { ['id']: Utils.uuid(query) },
- Utils.ilike(
- 'activities',
- 'subject',
- query,
- ),
- ],
- };
- }
-
- const records = await db.activities.findAll({
- attributes: [ 'id', 'subject' ],
- where,
- limit: limit ? Number(limit) : undefined,
- offset: offset ? Number(offset) : undefined,
- orderBy: [['subject', 'ASC']],
- });
-
- return records.map((record) => ({
- id: record.id,
- label: record.subject,
- }));
- }
-
-
-};
-
diff --git a/backend/src/db/api/contacts.js b/backend/src/db/api/contacts.js
deleted file mode 100644
index dec6100..0000000
--- a/backend/src/db/api/contacts.js
+++ /dev/null
@@ -1,636 +0,0 @@
-
-const db = require('../models');
-const FileDBApi = require('./file');
-const crypto = require('crypto');
-const Utils = require('../utils');
-
-
-
-const Sequelize = db.Sequelize;
-const Op = Sequelize.Op;
-
-module.exports = class ContactsDBApi {
-
-
-
- static async create(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const contacts = await db.contacts.create(
- {
- id: data.id || undefined,
-
- full_name: data.full_name
- ||
- null
- ,
-
- email: data.email
- ||
- null
- ,
-
- phone: data.phone
- ||
- null
- ,
-
- job_title: data.job_title
- ||
- null
- ,
-
- contact_status: data.contact_status
- ||
- null
- ,
-
- linkedin_url: data.linkedin_url
- ||
- null
- ,
-
- notes: data.notes
- ||
- null
- ,
-
- last_contacted_at: data.last_contacted_at
- ||
- null
- ,
-
- next_follow_up_at: data.next_follow_up_at
- ||
- null
- ,
-
- importHash: data.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- },
- { transaction },
- );
-
-
- await contacts.setAccount( data.account || null, {
- transaction,
- });
-
- await contacts.setOwner( data.owner || null, {
- transaction,
- });
-
-
-
-
-
-
- return contacts;
- }
-
-
- static async bulkImport(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- // Prepare data - wrapping individual data transformations in a map() method
- const contactsData = data.map((item, index) => ({
- id: item.id || undefined,
-
- full_name: item.full_name
- ||
- null
- ,
-
- email: item.email
- ||
- null
- ,
-
- phone: item.phone
- ||
- null
- ,
-
- job_title: item.job_title
- ||
- null
- ,
-
- contact_status: item.contact_status
- ||
- null
- ,
-
- linkedin_url: item.linkedin_url
- ||
- null
- ,
-
- notes: item.notes
- ||
- null
- ,
-
- last_contacted_at: item.last_contacted_at
- ||
- null
- ,
-
- next_follow_up_at: item.next_follow_up_at
- ||
- null
- ,
-
- importHash: item.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- createdAt: new Date(Date.now() + index * 1000),
- }));
-
- // Bulk create items
- const contacts = await db.contacts.bulkCreate(contactsData, { transaction });
-
- // For each item created, replace relation files
-
-
- return contacts;
- }
-
- static async update(id, data, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
-
- const contacts = await db.contacts.findByPk(id, {}, {transaction});
-
-
-
-
- const updatePayload = {};
-
- if (data.full_name !== undefined) updatePayload.full_name = data.full_name;
-
-
- if (data.email !== undefined) updatePayload.email = data.email;
-
-
- if (data.phone !== undefined) updatePayload.phone = data.phone;
-
-
- if (data.job_title !== undefined) updatePayload.job_title = data.job_title;
-
-
- if (data.contact_status !== undefined) updatePayload.contact_status = data.contact_status;
-
-
- if (data.linkedin_url !== undefined) updatePayload.linkedin_url = data.linkedin_url;
-
-
- if (data.notes !== undefined) updatePayload.notes = data.notes;
-
-
- if (data.last_contacted_at !== undefined) updatePayload.last_contacted_at = data.last_contacted_at;
-
-
- if (data.next_follow_up_at !== undefined) updatePayload.next_follow_up_at = data.next_follow_up_at;
-
-
- updatePayload.updatedById = currentUser.id;
-
- await contacts.update(updatePayload, {transaction});
-
-
-
- if (data.account !== undefined) {
- await contacts.setAccount(
-
- data.account,
-
- { transaction }
- );
- }
-
- if (data.owner !== undefined) {
- await contacts.setOwner(
-
- data.owner,
-
- { transaction }
- );
- }
-
-
-
-
-
-
-
- return contacts;
- }
-
- static async deleteByIds(ids, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const contacts = await db.contacts.findAll({
- where: {
- id: {
- [Op.in]: ids,
- },
- },
- transaction,
- });
-
- await db.sequelize.transaction(async (transaction) => {
- for (const record of contacts) {
- await record.update(
- {deletedBy: currentUser.id},
- {transaction}
- );
- }
- for (const record of contacts) {
- await record.destroy({transaction});
- }
- });
-
-
- return contacts;
- }
-
- static async remove(id, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
- const contacts = await db.contacts.findByPk(id, options);
-
- await contacts.update({
- deletedBy: currentUser.id
- }, {
- transaction,
- });
-
- await contacts.destroy({
- transaction
- });
-
- return contacts;
- }
-
- static async findBy(where, options) {
- const transaction = (options && options.transaction) || undefined;
-
- const contacts = await db.contacts.findOne(
- { where },
- { transaction },
- );
-
- if (!contacts) {
- return contacts;
- }
-
- const output = contacts.get({plain: true});
-
-
-
-
-
-
-
-
- output.leads_primary_contact = await contacts.getLeads_primary_contact({
- transaction
- });
-
-
-
- output.deals_primary_contact = await contacts.getDeals_primary_contact({
- transaction
- });
-
-
- output.activities_contact = await contacts.getActivities_contact({
- transaction
- });
-
-
-
- output.account = await contacts.getAccount({
- transaction
- });
-
-
- output.owner = await contacts.getOwner({
- transaction
- });
-
-
-
- return output;
- }
-
- static async findAll(
- filter,
- options
- ) {
- const limit = filter.limit || 0;
- let offset = 0;
- let where = {};
- const currentPage = +filter.page;
-
-
-
-
-
- offset = currentPage * limit;
-
- const orderBy = null;
-
- const transaction = (options && options.transaction) || undefined;
-
- let include = [
-
- {
- model: db.accounts,
- as: 'account',
-
- where: filter.account ? {
- [Op.or]: [
- { id: { [Op.in]: filter.account.split('|').map(term => Utils.uuid(term)) } },
- {
- name: {
- [Op.or]: filter.account.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.users,
- as: 'owner',
-
- where: filter.owner ? {
- [Op.or]: [
- { id: { [Op.in]: filter.owner.split('|').map(term => Utils.uuid(term)) } },
- {
- firstName: {
- [Op.or]: filter.owner.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
-
-
- ];
-
- if (filter) {
- if (filter.id) {
- where = {
- ...where,
- ['id']: Utils.uuid(filter.id),
- };
- }
-
-
- if (filter.full_name) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'contacts',
- 'full_name',
- filter.full_name,
- ),
- };
- }
-
- if (filter.email) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'contacts',
- 'email',
- filter.email,
- ),
- };
- }
-
- if (filter.phone) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'contacts',
- 'phone',
- filter.phone,
- ),
- };
- }
-
- if (filter.job_title) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'contacts',
- 'job_title',
- filter.job_title,
- ),
- };
- }
-
- if (filter.linkedin_url) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'contacts',
- 'linkedin_url',
- filter.linkedin_url,
- ),
- };
- }
-
- if (filter.notes) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'contacts',
- 'notes',
- filter.notes,
- ),
- };
- }
-
-
-
-
-
-
- if (filter.last_contacted_atRange) {
- const [start, end] = filter.last_contacted_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- last_contacted_at: {
- ...where.last_contacted_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- last_contacted_at: {
- ...where.last_contacted_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.next_follow_up_atRange) {
- const [start, end] = filter.next_follow_up_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- next_follow_up_at: {
- ...where.next_follow_up_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- next_follow_up_at: {
- ...where.next_follow_up_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
-
- if (filter.active !== undefined) {
- where = {
- ...where,
- active: filter.active === true || filter.active === 'true'
- };
- }
-
-
- if (filter.contact_status) {
- where = {
- ...where,
- contact_status: filter.contact_status,
- };
- }
-
-
-
-
-
-
-
-
-
- if (filter.createdAtRange) {
- const [start, end] = filter.createdAtRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.lte]: end,
- },
- };
- }
- }
- }
-
-
-
-
- const queryOptions = {
- where,
- include,
- distinct: true,
- order: filter.field && filter.sort
- ? [[filter.field, filter.sort]]
- : [['createdAt', 'desc']],
- transaction: options?.transaction,
- logging: console.log
- };
-
- if (!options?.countOnly) {
- queryOptions.limit = limit ? Number(limit) : undefined;
- queryOptions.offset = offset ? Number(offset) : undefined;
- }
-
- try {
- const { rows, count } = await db.contacts.findAndCountAll(queryOptions);
-
- return {
- rows: options?.countOnly ? [] : rows,
- count: count
- };
- } catch (error) {
- console.error('Error executing query:', error);
- throw error;
- }
- }
-
- static async findAllAutocomplete(query, limit, offset, ) {
- let where = {};
-
-
-
- if (query) {
- where = {
- [Op.or]: [
- { ['id']: Utils.uuid(query) },
- Utils.ilike(
- 'contacts',
- 'full_name',
- query,
- ),
- ],
- };
- }
-
- const records = await db.contacts.findAll({
- attributes: [ 'id', 'full_name' ],
- where,
- limit: limit ? Number(limit) : undefined,
- offset: offset ? Number(offset) : undefined,
- orderBy: [['full_name', 'ASC']],
- });
-
- return records.map((record) => ({
- id: record.id,
- label: record.full_name,
- }));
- }
-
-
-};
-
diff --git a/backend/src/db/api/deals.js b/backend/src/db/api/deals.js
deleted file mode 100644
index 0be9344..0000000
--- a/backend/src/db/api/deals.js
+++ /dev/null
@@ -1,802 +0,0 @@
-
-const db = require('../models');
-const FileDBApi = require('./file');
-const crypto = require('crypto');
-const Utils = require('../utils');
-
-
-
-const Sequelize = db.Sequelize;
-const Op = Sequelize.Op;
-
-module.exports = class DealsDBApi {
-
-
-
- static async create(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const deals = await db.deals.create(
- {
- id: data.id || undefined,
-
- name: data.name
- ||
- null
- ,
-
- amount: data.amount
- ||
- null
- ,
-
- currency: data.currency
- ||
- null
- ,
-
- expected_close_at: data.expected_close_at
- ||
- null
- ,
-
- closed_at: data.closed_at
- ||
- null
- ,
-
- deal_status: data.deal_status
- ||
- null
- ,
-
- loss_reason: data.loss_reason
- ||
- null
- ,
-
- last_activity_at: data.last_activity_at
- ||
- null
- ,
-
- next_follow_up_at: data.next_follow_up_at
- ||
- null
- ,
-
- description: data.description
- ||
- null
- ,
-
- importHash: data.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- },
- { transaction },
- );
-
-
- await deals.setStage( data.stage || null, {
- transaction,
- });
-
- await deals.setOwner( data.owner || null, {
- transaction,
- });
-
- await deals.setAccount( data.account || null, {
- transaction,
- });
-
- await deals.setPrimary_contact( data.primary_contact || null, {
- transaction,
- });
-
- await deals.setOriginating_lead( data.originating_lead || null, {
- transaction,
- });
-
-
-
-
-
-
- return deals;
- }
-
-
- static async bulkImport(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- // Prepare data - wrapping individual data transformations in a map() method
- const dealsData = data.map((item, index) => ({
- id: item.id || undefined,
-
- name: item.name
- ||
- null
- ,
-
- amount: item.amount
- ||
- null
- ,
-
- currency: item.currency
- ||
- null
- ,
-
- expected_close_at: item.expected_close_at
- ||
- null
- ,
-
- closed_at: item.closed_at
- ||
- null
- ,
-
- deal_status: item.deal_status
- ||
- null
- ,
-
- loss_reason: item.loss_reason
- ||
- null
- ,
-
- last_activity_at: item.last_activity_at
- ||
- null
- ,
-
- next_follow_up_at: item.next_follow_up_at
- ||
- null
- ,
-
- description: item.description
- ||
- null
- ,
-
- importHash: item.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- createdAt: new Date(Date.now() + index * 1000),
- }));
-
- // Bulk create items
- const deals = await db.deals.bulkCreate(dealsData, { transaction });
-
- // For each item created, replace relation files
-
-
- return deals;
- }
-
- static async update(id, data, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
-
- const deals = await db.deals.findByPk(id, {}, {transaction});
-
-
-
-
- const updatePayload = {};
-
- if (data.name !== undefined) updatePayload.name = data.name;
-
-
- if (data.amount !== undefined) updatePayload.amount = data.amount;
-
-
- if (data.currency !== undefined) updatePayload.currency = data.currency;
-
-
- if (data.expected_close_at !== undefined) updatePayload.expected_close_at = data.expected_close_at;
-
-
- if (data.closed_at !== undefined) updatePayload.closed_at = data.closed_at;
-
-
- if (data.deal_status !== undefined) updatePayload.deal_status = data.deal_status;
-
-
- if (data.loss_reason !== undefined) updatePayload.loss_reason = data.loss_reason;
-
-
- if (data.last_activity_at !== undefined) updatePayload.last_activity_at = data.last_activity_at;
-
-
- if (data.next_follow_up_at !== undefined) updatePayload.next_follow_up_at = data.next_follow_up_at;
-
-
- if (data.description !== undefined) updatePayload.description = data.description;
-
-
- updatePayload.updatedById = currentUser.id;
-
- await deals.update(updatePayload, {transaction});
-
-
-
- if (data.stage !== undefined) {
- await deals.setStage(
-
- data.stage,
-
- { transaction }
- );
- }
-
- if (data.owner !== undefined) {
- await deals.setOwner(
-
- data.owner,
-
- { transaction }
- );
- }
-
- if (data.account !== undefined) {
- await deals.setAccount(
-
- data.account,
-
- { transaction }
- );
- }
-
- if (data.primary_contact !== undefined) {
- await deals.setPrimary_contact(
-
- data.primary_contact,
-
- { transaction }
- );
- }
-
- if (data.originating_lead !== undefined) {
- await deals.setOriginating_lead(
-
- data.originating_lead,
-
- { transaction }
- );
- }
-
-
-
-
-
-
-
- return deals;
- }
-
- static async deleteByIds(ids, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const deals = await db.deals.findAll({
- where: {
- id: {
- [Op.in]: ids,
- },
- },
- transaction,
- });
-
- await db.sequelize.transaction(async (transaction) => {
- for (const record of deals) {
- await record.update(
- {deletedBy: currentUser.id},
- {transaction}
- );
- }
- for (const record of deals) {
- await record.destroy({transaction});
- }
- });
-
-
- return deals;
- }
-
- static async remove(id, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
- const deals = await db.deals.findByPk(id, options);
-
- await deals.update({
- deletedBy: currentUser.id
- }, {
- transaction,
- });
-
- await deals.destroy({
- transaction
- });
-
- return deals;
- }
-
- static async findBy(where, options) {
- const transaction = (options && options.transaction) || undefined;
-
- const deals = await db.deals.findOne(
- { where },
- { transaction },
- );
-
- if (!deals) {
- return deals;
- }
-
- const output = deals.get({plain: true});
-
-
-
-
-
-
-
-
-
-
-
- output.activities_deal = await deals.getActivities_deal({
- transaction
- });
-
-
-
- output.stage = await deals.getStage({
- transaction
- });
-
-
- output.owner = await deals.getOwner({
- transaction
- });
-
-
- output.account = await deals.getAccount({
- transaction
- });
-
-
- output.primary_contact = await deals.getPrimary_contact({
- transaction
- });
-
-
- output.originating_lead = await deals.getOriginating_lead({
- transaction
- });
-
-
-
- return output;
- }
-
- static async findAll(
- filter,
- options
- ) {
- const limit = filter.limit || 0;
- let offset = 0;
- let where = {};
- const currentPage = +filter.page;
-
-
-
-
-
- offset = currentPage * limit;
-
- const orderBy = null;
-
- const transaction = (options && options.transaction) || undefined;
-
- let include = [
-
- {
- model: db.pipeline_stages,
- as: 'stage',
-
- where: filter.stage ? {
- [Op.or]: [
- { id: { [Op.in]: filter.stage.split('|').map(term => Utils.uuid(term)) } },
- {
- name: {
- [Op.or]: filter.stage.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.users,
- as: 'owner',
-
- where: filter.owner ? {
- [Op.or]: [
- { id: { [Op.in]: filter.owner.split('|').map(term => Utils.uuid(term)) } },
- {
- firstName: {
- [Op.or]: filter.owner.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.accounts,
- as: 'account',
-
- where: filter.account ? {
- [Op.or]: [
- { id: { [Op.in]: filter.account.split('|').map(term => Utils.uuid(term)) } },
- {
- name: {
- [Op.or]: filter.account.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.contacts,
- as: 'primary_contact',
-
- where: filter.primary_contact ? {
- [Op.or]: [
- { id: { [Op.in]: filter.primary_contact.split('|').map(term => Utils.uuid(term)) } },
- {
- full_name: {
- [Op.or]: filter.primary_contact.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.leads,
- as: 'originating_lead',
-
- where: filter.originating_lead ? {
- [Op.or]: [
- { id: { [Op.in]: filter.originating_lead.split('|').map(term => Utils.uuid(term)) } },
- {
- lead_name: {
- [Op.or]: filter.originating_lead.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
-
-
- ];
-
- if (filter) {
- if (filter.id) {
- where = {
- ...where,
- ['id']: Utils.uuid(filter.id),
- };
- }
-
-
- if (filter.name) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'deals',
- 'name',
- filter.name,
- ),
- };
- }
-
- if (filter.currency) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'deals',
- 'currency',
- filter.currency,
- ),
- };
- }
-
- if (filter.loss_reason) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'deals',
- 'loss_reason',
- filter.loss_reason,
- ),
- };
- }
-
- if (filter.description) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'deals',
- 'description',
- filter.description,
- ),
- };
- }
-
-
-
-
-
-
- if (filter.amountRange) {
- const [start, end] = filter.amountRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- amount: {
- ...where.amount,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- amount: {
- ...where.amount,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.expected_close_atRange) {
- const [start, end] = filter.expected_close_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- expected_close_at: {
- ...where.expected_close_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- expected_close_at: {
- ...where.expected_close_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.closed_atRange) {
- const [start, end] = filter.closed_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- closed_at: {
- ...where.closed_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- closed_at: {
- ...where.closed_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.last_activity_atRange) {
- const [start, end] = filter.last_activity_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- last_activity_at: {
- ...where.last_activity_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- last_activity_at: {
- ...where.last_activity_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.next_follow_up_atRange) {
- const [start, end] = filter.next_follow_up_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- next_follow_up_at: {
- ...where.next_follow_up_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- next_follow_up_at: {
- ...where.next_follow_up_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
-
- if (filter.active !== undefined) {
- where = {
- ...where,
- active: filter.active === true || filter.active === 'true'
- };
- }
-
-
- if (filter.deal_status) {
- where = {
- ...where,
- deal_status: filter.deal_status,
- };
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (filter.createdAtRange) {
- const [start, end] = filter.createdAtRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.lte]: end,
- },
- };
- }
- }
- }
-
-
-
-
- const queryOptions = {
- where,
- include,
- distinct: true,
- order: filter.field && filter.sort
- ? [[filter.field, filter.sort]]
- : [['createdAt', 'desc']],
- transaction: options?.transaction,
- logging: console.log
- };
-
- if (!options?.countOnly) {
- queryOptions.limit = limit ? Number(limit) : undefined;
- queryOptions.offset = offset ? Number(offset) : undefined;
- }
-
- try {
- const { rows, count } = await db.deals.findAndCountAll(queryOptions);
-
- return {
- rows: options?.countOnly ? [] : rows,
- count: count
- };
- } catch (error) {
- console.error('Error executing query:', error);
- throw error;
- }
- }
-
- static async findAllAutocomplete(query, limit, offset, ) {
- let where = {};
-
-
-
- if (query) {
- where = {
- [Op.or]: [
- { ['id']: Utils.uuid(query) },
- Utils.ilike(
- 'deals',
- 'name',
- query,
- ),
- ],
- };
- }
-
- const records = await db.deals.findAll({
- attributes: [ 'id', 'name' ],
- where,
- limit: limit ? Number(limit) : undefined,
- offset: offset ? Number(offset) : undefined,
- orderBy: [['name', 'ASC']],
- });
-
- return records.map((record) => ({
- id: record.id,
- label: record.name,
- }));
- }
-
-
-};
-
diff --git a/backend/src/db/api/lead_sources.js b/backend/src/db/api/lead_sources.js
deleted file mode 100644
index 91f688e..0000000
--- a/backend/src/db/api/lead_sources.js
+++ /dev/null
@@ -1,386 +0,0 @@
-
-const db = require('../models');
-const FileDBApi = require('./file');
-const crypto = require('crypto');
-const Utils = require('../utils');
-
-
-
-const Sequelize = db.Sequelize;
-const Op = Sequelize.Op;
-
-module.exports = class Lead_sourcesDBApi {
-
-
-
- static async create(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const lead_sources = await db.lead_sources.create(
- {
- id: data.id || undefined,
-
- name: data.name
- ||
- null
- ,
-
- is_active: data.is_active
- ||
- false
-
- ,
-
- description: data.description
- ||
- null
- ,
-
- importHash: data.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- },
- { transaction },
- );
-
-
-
-
-
-
-
- return lead_sources;
- }
-
-
- static async bulkImport(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- // Prepare data - wrapping individual data transformations in a map() method
- const lead_sourcesData = data.map((item, index) => ({
- id: item.id || undefined,
-
- name: item.name
- ||
- null
- ,
-
- is_active: item.is_active
- ||
- false
-
- ,
-
- description: item.description
- ||
- null
- ,
-
- importHash: item.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- createdAt: new Date(Date.now() + index * 1000),
- }));
-
- // Bulk create items
- const lead_sources = await db.lead_sources.bulkCreate(lead_sourcesData, { transaction });
-
- // For each item created, replace relation files
-
-
- return lead_sources;
- }
-
- static async update(id, data, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
-
- const lead_sources = await db.lead_sources.findByPk(id, {}, {transaction});
-
-
-
-
- const updatePayload = {};
-
- if (data.name !== undefined) updatePayload.name = data.name;
-
-
- if (data.is_active !== undefined) updatePayload.is_active = data.is_active;
-
-
- if (data.description !== undefined) updatePayload.description = data.description;
-
-
- updatePayload.updatedById = currentUser.id;
-
- await lead_sources.update(updatePayload, {transaction});
-
-
-
-
-
-
-
-
-
- return lead_sources;
- }
-
- static async deleteByIds(ids, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const lead_sources = await db.lead_sources.findAll({
- where: {
- id: {
- [Op.in]: ids,
- },
- },
- transaction,
- });
-
- await db.sequelize.transaction(async (transaction) => {
- for (const record of lead_sources) {
- await record.update(
- {deletedBy: currentUser.id},
- {transaction}
- );
- }
- for (const record of lead_sources) {
- await record.destroy({transaction});
- }
- });
-
-
- return lead_sources;
- }
-
- static async remove(id, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
- const lead_sources = await db.lead_sources.findByPk(id, options);
-
- await lead_sources.update({
- deletedBy: currentUser.id
- }, {
- transaction,
- });
-
- await lead_sources.destroy({
- transaction
- });
-
- return lead_sources;
- }
-
- static async findBy(where, options) {
- const transaction = (options && options.transaction) || undefined;
-
- const lead_sources = await db.lead_sources.findOne(
- { where },
- { transaction },
- );
-
- if (!lead_sources) {
- return lead_sources;
- }
-
- const output = lead_sources.get({plain: true});
-
-
-
-
-
-
-
-
- output.leads_source = await lead_sources.getLeads_source({
- transaction
- });
-
-
-
-
-
-
-
- return output;
- }
-
- static async findAll(
- filter,
- options
- ) {
- const limit = filter.limit || 0;
- let offset = 0;
- let where = {};
- const currentPage = +filter.page;
-
-
-
-
-
- offset = currentPage * limit;
-
- const orderBy = null;
-
- const transaction = (options && options.transaction) || undefined;
-
- let include = [
-
-
-
- ];
-
- if (filter) {
- if (filter.id) {
- where = {
- ...where,
- ['id']: Utils.uuid(filter.id),
- };
- }
-
-
- if (filter.name) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'lead_sources',
- 'name',
- filter.name,
- ),
- };
- }
-
- if (filter.description) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'lead_sources',
- 'description',
- filter.description,
- ),
- };
- }
-
-
-
-
-
-
-
- if (filter.active !== undefined) {
- where = {
- ...where,
- active: filter.active === true || filter.active === 'true'
- };
- }
-
-
- if (filter.is_active) {
- where = {
- ...where,
- is_active: filter.is_active,
- };
- }
-
-
-
-
-
- if (filter.createdAtRange) {
- const [start, end] = filter.createdAtRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.lte]: end,
- },
- };
- }
- }
- }
-
-
-
-
- const queryOptions = {
- where,
- include,
- distinct: true,
- order: filter.field && filter.sort
- ? [[filter.field, filter.sort]]
- : [['createdAt', 'desc']],
- transaction: options?.transaction,
- logging: console.log
- };
-
- if (!options?.countOnly) {
- queryOptions.limit = limit ? Number(limit) : undefined;
- queryOptions.offset = offset ? Number(offset) : undefined;
- }
-
- try {
- const { rows, count } = await db.lead_sources.findAndCountAll(queryOptions);
-
- return {
- rows: options?.countOnly ? [] : rows,
- count: count
- };
- } catch (error) {
- console.error('Error executing query:', error);
- throw error;
- }
- }
-
- static async findAllAutocomplete(query, limit, offset, ) {
- let where = {};
-
-
-
- if (query) {
- where = {
- [Op.or]: [
- { ['id']: Utils.uuid(query) },
- Utils.ilike(
- 'lead_sources',
- 'name',
- query,
- ),
- ],
- };
- }
-
- const records = await db.lead_sources.findAll({
- attributes: [ 'id', 'name' ],
- where,
- limit: limit ? Number(limit) : undefined,
- offset: offset ? Number(offset) : undefined,
- orderBy: [['name', 'ASC']],
- });
-
- return records.map((record) => ({
- id: record.id,
- label: record.name,
- }));
- }
-
-
-};
-
diff --git a/backend/src/db/api/leads.js b/backend/src/db/api/leads.js
deleted file mode 100644
index 907201f..0000000
--- a/backend/src/db/api/leads.js
+++ /dev/null
@@ -1,702 +0,0 @@
-
-const db = require('../models');
-const FileDBApi = require('./file');
-const crypto = require('crypto');
-const Utils = require('../utils');
-
-
-
-const Sequelize = db.Sequelize;
-const Op = Sequelize.Op;
-
-module.exports = class LeadsDBApi {
-
-
-
- static async create(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const leads = await db.leads.create(
- {
- id: data.id || undefined,
-
- lead_name: data.lead_name
- ||
- null
- ,
-
- company_name: data.company_name
- ||
- null
- ,
-
- email: data.email
- ||
- null
- ,
-
- phone: data.phone
- ||
- null
- ,
-
- lead_status: data.lead_status
- ||
- null
- ,
-
- lead_rating: data.lead_rating
- ||
- null
- ,
-
- notes: data.notes
- ||
- null
- ,
-
- last_contacted_at: data.last_contacted_at
- ||
- null
- ,
-
- next_follow_up_at: data.next_follow_up_at
- ||
- null
- ,
-
- importHash: data.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- },
- { transaction },
- );
-
-
- await leads.setOwner( data.owner || null, {
- transaction,
- });
-
- await leads.setSource( data.source || null, {
- transaction,
- });
-
- await leads.setAccount( data.account || null, {
- transaction,
- });
-
- await leads.setPrimary_contact( data.primary_contact || null, {
- transaction,
- });
-
-
-
-
-
-
- return leads;
- }
-
-
- static async bulkImport(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- // Prepare data - wrapping individual data transformations in a map() method
- const leadsData = data.map((item, index) => ({
- id: item.id || undefined,
-
- lead_name: item.lead_name
- ||
- null
- ,
-
- company_name: item.company_name
- ||
- null
- ,
-
- email: item.email
- ||
- null
- ,
-
- phone: item.phone
- ||
- null
- ,
-
- lead_status: item.lead_status
- ||
- null
- ,
-
- lead_rating: item.lead_rating
- ||
- null
- ,
-
- notes: item.notes
- ||
- null
- ,
-
- last_contacted_at: item.last_contacted_at
- ||
- null
- ,
-
- next_follow_up_at: item.next_follow_up_at
- ||
- null
- ,
-
- importHash: item.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- createdAt: new Date(Date.now() + index * 1000),
- }));
-
- // Bulk create items
- const leads = await db.leads.bulkCreate(leadsData, { transaction });
-
- // For each item created, replace relation files
-
-
- return leads;
- }
-
- static async update(id, data, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
-
- const leads = await db.leads.findByPk(id, {}, {transaction});
-
-
-
-
- const updatePayload = {};
-
- if (data.lead_name !== undefined) updatePayload.lead_name = data.lead_name;
-
-
- if (data.company_name !== undefined) updatePayload.company_name = data.company_name;
-
-
- if (data.email !== undefined) updatePayload.email = data.email;
-
-
- if (data.phone !== undefined) updatePayload.phone = data.phone;
-
-
- if (data.lead_status !== undefined) updatePayload.lead_status = data.lead_status;
-
-
- if (data.lead_rating !== undefined) updatePayload.lead_rating = data.lead_rating;
-
-
- if (data.notes !== undefined) updatePayload.notes = data.notes;
-
-
- if (data.last_contacted_at !== undefined) updatePayload.last_contacted_at = data.last_contacted_at;
-
-
- if (data.next_follow_up_at !== undefined) updatePayload.next_follow_up_at = data.next_follow_up_at;
-
-
- updatePayload.updatedById = currentUser.id;
-
- await leads.update(updatePayload, {transaction});
-
-
-
- if (data.owner !== undefined) {
- await leads.setOwner(
-
- data.owner,
-
- { transaction }
- );
- }
-
- if (data.source !== undefined) {
- await leads.setSource(
-
- data.source,
-
- { transaction }
- );
- }
-
- if (data.account !== undefined) {
- await leads.setAccount(
-
- data.account,
-
- { transaction }
- );
- }
-
- if (data.primary_contact !== undefined) {
- await leads.setPrimary_contact(
-
- data.primary_contact,
-
- { transaction }
- );
- }
-
-
-
-
-
-
-
- return leads;
- }
-
- static async deleteByIds(ids, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const leads = await db.leads.findAll({
- where: {
- id: {
- [Op.in]: ids,
- },
- },
- transaction,
- });
-
- await db.sequelize.transaction(async (transaction) => {
- for (const record of leads) {
- await record.update(
- {deletedBy: currentUser.id},
- {transaction}
- );
- }
- for (const record of leads) {
- await record.destroy({transaction});
- }
- });
-
-
- return leads;
- }
-
- static async remove(id, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
- const leads = await db.leads.findByPk(id, options);
-
- await leads.update({
- deletedBy: currentUser.id
- }, {
- transaction,
- });
-
- await leads.destroy({
- transaction
- });
-
- return leads;
- }
-
- static async findBy(where, options) {
- const transaction = (options && options.transaction) || undefined;
-
- const leads = await db.leads.findOne(
- { where },
- { transaction },
- );
-
- if (!leads) {
- return leads;
- }
-
- const output = leads.get({plain: true});
-
-
-
-
-
-
-
-
-
-
- output.deals_originating_lead = await leads.getDeals_originating_lead({
- transaction
- });
-
-
- output.activities_lead = await leads.getActivities_lead({
- transaction
- });
-
-
-
- output.owner = await leads.getOwner({
- transaction
- });
-
-
- output.source = await leads.getSource({
- transaction
- });
-
-
- output.account = await leads.getAccount({
- transaction
- });
-
-
- output.primary_contact = await leads.getPrimary_contact({
- transaction
- });
-
-
-
- return output;
- }
-
- static async findAll(
- filter,
- options
- ) {
- const limit = filter.limit || 0;
- let offset = 0;
- let where = {};
- const currentPage = +filter.page;
-
-
-
-
-
- offset = currentPage * limit;
-
- const orderBy = null;
-
- const transaction = (options && options.transaction) || undefined;
-
- let include = [
-
- {
- model: db.users,
- as: 'owner',
-
- where: filter.owner ? {
- [Op.or]: [
- { id: { [Op.in]: filter.owner.split('|').map(term => Utils.uuid(term)) } },
- {
- firstName: {
- [Op.or]: filter.owner.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.lead_sources,
- as: 'source',
-
- where: filter.source ? {
- [Op.or]: [
- { id: { [Op.in]: filter.source.split('|').map(term => Utils.uuid(term)) } },
- {
- name: {
- [Op.or]: filter.source.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.accounts,
- as: 'account',
-
- where: filter.account ? {
- [Op.or]: [
- { id: { [Op.in]: filter.account.split('|').map(term => Utils.uuid(term)) } },
- {
- name: {
- [Op.or]: filter.account.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
- {
- model: db.contacts,
- as: 'primary_contact',
-
- where: filter.primary_contact ? {
- [Op.or]: [
- { id: { [Op.in]: filter.primary_contact.split('|').map(term => Utils.uuid(term)) } },
- {
- full_name: {
- [Op.or]: filter.primary_contact.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
- }
- },
- ]
- } : {},
-
- },
-
-
-
- ];
-
- if (filter) {
- if (filter.id) {
- where = {
- ...where,
- ['id']: Utils.uuid(filter.id),
- };
- }
-
-
- if (filter.lead_name) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'leads',
- 'lead_name',
- filter.lead_name,
- ),
- };
- }
-
- if (filter.company_name) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'leads',
- 'company_name',
- filter.company_name,
- ),
- };
- }
-
- if (filter.email) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'leads',
- 'email',
- filter.email,
- ),
- };
- }
-
- if (filter.phone) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'leads',
- 'phone',
- filter.phone,
- ),
- };
- }
-
- if (filter.notes) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'leads',
- 'notes',
- filter.notes,
- ),
- };
- }
-
-
-
-
-
-
- if (filter.last_contacted_atRange) {
- const [start, end] = filter.last_contacted_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- last_contacted_at: {
- ...where.last_contacted_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- last_contacted_at: {
- ...where.last_contacted_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.next_follow_up_atRange) {
- const [start, end] = filter.next_follow_up_atRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- next_follow_up_at: {
- ...where.next_follow_up_at,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- next_follow_up_at: {
- ...where.next_follow_up_at,
- [Op.lte]: end,
- },
- };
- }
- }
-
-
- if (filter.active !== undefined) {
- where = {
- ...where,
- active: filter.active === true || filter.active === 'true'
- };
- }
-
-
- if (filter.lead_status) {
- where = {
- ...where,
- lead_status: filter.lead_status,
- };
- }
-
- if (filter.lead_rating) {
- where = {
- ...where,
- lead_rating: filter.lead_rating,
- };
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (filter.createdAtRange) {
- const [start, end] = filter.createdAtRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.lte]: end,
- },
- };
- }
- }
- }
-
-
-
-
- const queryOptions = {
- where,
- include,
- distinct: true,
- order: filter.field && filter.sort
- ? [[filter.field, filter.sort]]
- : [['createdAt', 'desc']],
- transaction: options?.transaction,
- logging: console.log
- };
-
- if (!options?.countOnly) {
- queryOptions.limit = limit ? Number(limit) : undefined;
- queryOptions.offset = offset ? Number(offset) : undefined;
- }
-
- try {
- const { rows, count } = await db.leads.findAndCountAll(queryOptions);
-
- return {
- rows: options?.countOnly ? [] : rows,
- count: count
- };
- } catch (error) {
- console.error('Error executing query:', error);
- throw error;
- }
- }
-
- static async findAllAutocomplete(query, limit, offset, ) {
- let where = {};
-
-
-
- if (query) {
- where = {
- [Op.or]: [
- { ['id']: Utils.uuid(query) },
- Utils.ilike(
- 'leads',
- 'lead_name',
- query,
- ),
- ],
- };
- }
-
- const records = await db.leads.findAll({
- attributes: [ 'id', 'lead_name' ],
- where,
- limit: limit ? Number(limit) : undefined,
- offset: offset ? Number(offset) : undefined,
- orderBy: [['lead_name', 'ASC']],
- });
-
- return records.map((record) => ({
- id: record.id,
- label: record.lead_name,
- }));
- }
-
-
-};
-
diff --git a/backend/src/db/api/pipeline_stages.js b/backend/src/db/api/pipeline_stages.js
deleted file mode 100644
index 8774038..0000000
--- a/backend/src/db/api/pipeline_stages.js
+++ /dev/null
@@ -1,480 +0,0 @@
-
-const db = require('../models');
-const FileDBApi = require('./file');
-const crypto = require('crypto');
-const Utils = require('../utils');
-
-
-
-const Sequelize = db.Sequelize;
-const Op = Sequelize.Op;
-
-module.exports = class Pipeline_stagesDBApi {
-
-
-
- static async create(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const pipeline_stages = await db.pipeline_stages.create(
- {
- id: data.id || undefined,
-
- name: data.name
- ||
- null
- ,
-
- sort_order: data.sort_order
- ||
- null
- ,
-
- win_probability: data.win_probability
- ||
- null
- ,
-
- is_won: data.is_won
- ||
- false
-
- ,
-
- is_lost: data.is_lost
- ||
- false
-
- ,
-
- is_active: data.is_active
- ||
- false
-
- ,
-
- importHash: data.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- },
- { transaction },
- );
-
-
-
-
-
-
-
- return pipeline_stages;
- }
-
-
- static async bulkImport(data, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- // Prepare data - wrapping individual data transformations in a map() method
- const pipeline_stagesData = data.map((item, index) => ({
- id: item.id || undefined,
-
- name: item.name
- ||
- null
- ,
-
- sort_order: item.sort_order
- ||
- null
- ,
-
- win_probability: item.win_probability
- ||
- null
- ,
-
- is_won: item.is_won
- ||
- false
-
- ,
-
- is_lost: item.is_lost
- ||
- false
-
- ,
-
- is_active: item.is_active
- ||
- false
-
- ,
-
- importHash: item.importHash || null,
- createdById: currentUser.id,
- updatedById: currentUser.id,
- createdAt: new Date(Date.now() + index * 1000),
- }));
-
- // Bulk create items
- const pipeline_stages = await db.pipeline_stages.bulkCreate(pipeline_stagesData, { transaction });
-
- // For each item created, replace relation files
-
-
- return pipeline_stages;
- }
-
- static async update(id, data, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
-
- const pipeline_stages = await db.pipeline_stages.findByPk(id, {}, {transaction});
-
-
-
-
- const updatePayload = {};
-
- if (data.name !== undefined) updatePayload.name = data.name;
-
-
- if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order;
-
-
- if (data.win_probability !== undefined) updatePayload.win_probability = data.win_probability;
-
-
- if (data.is_won !== undefined) updatePayload.is_won = data.is_won;
-
-
- if (data.is_lost !== undefined) updatePayload.is_lost = data.is_lost;
-
-
- if (data.is_active !== undefined) updatePayload.is_active = data.is_active;
-
-
- updatePayload.updatedById = currentUser.id;
-
- await pipeline_stages.update(updatePayload, {transaction});
-
-
-
-
-
-
-
-
-
- return pipeline_stages;
- }
-
- static async deleteByIds(ids, options) {
- const currentUser = (options && options.currentUser) || { id: null };
- const transaction = (options && options.transaction) || undefined;
-
- const pipeline_stages = await db.pipeline_stages.findAll({
- where: {
- id: {
- [Op.in]: ids,
- },
- },
- transaction,
- });
-
- await db.sequelize.transaction(async (transaction) => {
- for (const record of pipeline_stages) {
- await record.update(
- {deletedBy: currentUser.id},
- {transaction}
- );
- }
- for (const record of pipeline_stages) {
- await record.destroy({transaction});
- }
- });
-
-
- return pipeline_stages;
- }
-
- static async remove(id, options) {
- const currentUser = (options && options.currentUser) || {id: null};
- const transaction = (options && options.transaction) || undefined;
-
- const pipeline_stages = await db.pipeline_stages.findByPk(id, options);
-
- await pipeline_stages.update({
- deletedBy: currentUser.id
- }, {
- transaction,
- });
-
- await pipeline_stages.destroy({
- transaction
- });
-
- return pipeline_stages;
- }
-
- static async findBy(where, options) {
- const transaction = (options && options.transaction) || undefined;
-
- const pipeline_stages = await db.pipeline_stages.findOne(
- { where },
- { transaction },
- );
-
- if (!pipeline_stages) {
- return pipeline_stages;
- }
-
- const output = pipeline_stages.get({plain: true});
-
-
-
-
-
-
-
-
-
-
- output.deals_stage = await pipeline_stages.getDeals_stage({
- transaction
- });
-
-
-
-
-
- return output;
- }
-
- static async findAll(
- filter,
- options
- ) {
- const limit = filter.limit || 0;
- let offset = 0;
- let where = {};
- const currentPage = +filter.page;
-
-
-
-
-
- offset = currentPage * limit;
-
- const orderBy = null;
-
- const transaction = (options && options.transaction) || undefined;
-
- let include = [
-
-
-
- ];
-
- if (filter) {
- if (filter.id) {
- where = {
- ...where,
- ['id']: Utils.uuid(filter.id),
- };
- }
-
-
- if (filter.name) {
- where = {
- ...where,
- [Op.and]: Utils.ilike(
- 'pipeline_stages',
- 'name',
- filter.name,
- ),
- };
- }
-
-
-
-
-
-
- if (filter.sort_orderRange) {
- const [start, end] = filter.sort_orderRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- sort_order: {
- ...where.sort_order,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- sort_order: {
- ...where.sort_order,
- [Op.lte]: end,
- },
- };
- }
- }
-
- if (filter.win_probabilityRange) {
- const [start, end] = filter.win_probabilityRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- win_probability: {
- ...where.win_probability,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- win_probability: {
- ...where.win_probability,
- [Op.lte]: end,
- },
- };
- }
- }
-
-
- if (filter.active !== undefined) {
- where = {
- ...where,
- active: filter.active === true || filter.active === 'true'
- };
- }
-
-
- if (filter.is_won) {
- where = {
- ...where,
- is_won: filter.is_won,
- };
- }
-
- if (filter.is_lost) {
- where = {
- ...where,
- is_lost: filter.is_lost,
- };
- }
-
- if (filter.is_active) {
- where = {
- ...where,
- is_active: filter.is_active,
- };
- }
-
-
-
-
-
- if (filter.createdAtRange) {
- const [start, end] = filter.createdAtRange;
-
- if (start !== undefined && start !== null && start !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.gte]: start,
- },
- };
- }
-
- if (end !== undefined && end !== null && end !== '') {
- where = {
- ...where,
- ['createdAt']: {
- ...where.createdAt,
- [Op.lte]: end,
- },
- };
- }
- }
- }
-
-
-
-
- const queryOptions = {
- where,
- include,
- distinct: true,
- order: filter.field && filter.sort
- ? [[filter.field, filter.sort]]
- : [['createdAt', 'desc']],
- transaction: options?.transaction,
- logging: console.log
- };
-
- if (!options?.countOnly) {
- queryOptions.limit = limit ? Number(limit) : undefined;
- queryOptions.offset = offset ? Number(offset) : undefined;
- }
-
- try {
- const { rows, count } = await db.pipeline_stages.findAndCountAll(queryOptions);
-
- return {
- rows: options?.countOnly ? [] : rows,
- count: count
- };
- } catch (error) {
- console.error('Error executing query:', error);
- throw error;
- }
- }
-
- static async findAllAutocomplete(query, limit, offset, ) {
- let where = {};
-
-
-
- if (query) {
- where = {
- [Op.or]: [
- { ['id']: Utils.uuid(query) },
- Utils.ilike(
- 'pipeline_stages',
- 'name',
- query,
- ),
- ],
- };
- }
-
- const records = await db.pipeline_stages.findAll({
- attributes: [ 'id', 'name' ],
- where,
- limit: limit ? Number(limit) : undefined,
- offset: offset ? Number(offset) : undefined,
- orderBy: [['name', 'ASC']],
- });
-
- return records.map((record) => ({
- id: record.id,
- label: record.name,
- }));
- }
-
-
-};
-
diff --git a/backend/src/db/models/accounts.js b/backend/src/db/models/accounts.js
deleted file mode 100644
index b40e875..0000000
--- a/backend/src/db/models/accounts.js
+++ /dev/null
@@ -1,207 +0,0 @@
-const config = require('../../config');
-const providers = config.providers;
-const crypto = require('crypto');
-const bcrypt = require('bcrypt');
-const moment = require('moment');
-
-module.exports = function(sequelize, DataTypes) {
- const accounts = sequelize.define(
- 'accounts',
- {
- id: {
- type: DataTypes.UUID,
- defaultValue: DataTypes.UUIDV4,
- primaryKey: true,
- },
-
-name: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-domain: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-industry: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-employee_count: {
- type: DataTypes.INTEGER,
-
-
-
- },
-
-annual_revenue: {
- type: DataTypes.DECIMAL,
-
-
-
- },
-
-phone: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-website: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-address: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-account_status: {
- type: DataTypes.ENUM,
-
-
-
- values: [
-
-"prospect",
-
-
-"active_customer",
-
-
-"former_customer",
-
-
-"partner"
-
- ],
-
- },
-
-last_contacted_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-next_follow_up_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-notes: {
- type: DataTypes.TEXT,
-
-
-
- },
-
- importHash: {
- type: DataTypes.STRING(255),
- allowNull: true,
- unique: true,
- },
- },
- {
- timestamps: true,
- paranoid: true,
- freezeTableName: true,
- },
- );
-
- accounts.associate = (db) => {
-
-
-/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
-
-
-
-
-
-
- db.accounts.hasMany(db.contacts, {
- as: 'contacts_account',
- foreignKey: {
- name: 'accountId',
- },
- constraints: false,
- });
-
-
-
- db.accounts.hasMany(db.leads, {
- as: 'leads_account',
- foreignKey: {
- name: 'accountId',
- },
- constraints: false,
- });
-
-
-
- db.accounts.hasMany(db.deals, {
- as: 'deals_account',
- foreignKey: {
- name: 'accountId',
- },
- constraints: false,
- });
-
-
- db.accounts.hasMany(db.activities, {
- as: 'activities_account',
- foreignKey: {
- name: 'accountId',
- },
- constraints: false,
- });
-
-
-
-//end loop
-
-
-
- db.accounts.belongsTo(db.users, {
- as: 'owner',
- foreignKey: {
- name: 'ownerId',
- },
- constraints: false,
- });
-
-
-
-
- db.accounts.belongsTo(db.users, {
- as: 'createdBy',
- });
-
- db.accounts.belongsTo(db.users, {
- as: 'updatedBy',
- });
- };
-
-
-
- return accounts;
-};
-
-
diff --git a/backend/src/db/models/activities.js b/backend/src/db/models/activities.js
deleted file mode 100644
index 870b89e..0000000
--- a/backend/src/db/models/activities.js
+++ /dev/null
@@ -1,216 +0,0 @@
-const config = require('../../config');
-const providers = config.providers;
-const crypto = require('crypto');
-const bcrypt = require('bcrypt');
-const moment = require('moment');
-
-module.exports = function(sequelize, DataTypes) {
- const activities = sequelize.define(
- 'activities',
- {
- id: {
- type: DataTypes.UUID,
- defaultValue: DataTypes.UUIDV4,
- primaryKey: true,
- },
-
-activity_type: {
- type: DataTypes.ENUM,
-
-
-
- values: [
-
-"call",
-
-
-"email",
-
-
-"meeting",
-
-
-"task",
-
-
-"note"
-
- ],
-
- },
-
-subject: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-details: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-activity_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-due_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-completed_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-status: {
- type: DataTypes.ENUM,
-
-
-
- values: [
-
-"planned",
-
-
-"completed",
-
-
-"canceled"
-
- ],
-
- },
-
-priority: {
- type: DataTypes.ENUM,
-
-
-
- values: [
-
-"low",
-
-
-"medium",
-
-
-"high"
-
- ],
-
- },
-
- importHash: {
- type: DataTypes.STRING(255),
- allowNull: true,
- unique: true,
- },
- },
- {
- timestamps: true,
- paranoid: true,
- freezeTableName: true,
- },
- );
-
- activities.associate = (db) => {
-
-
-/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
-
-
-
-
-
-
-
-
-
-
-
-
-
-//end loop
-
-
-
- db.activities.belongsTo(db.users, {
- as: 'owner',
- foreignKey: {
- name: 'ownerId',
- },
- constraints: false,
- });
-
- db.activities.belongsTo(db.leads, {
- as: 'lead',
- foreignKey: {
- name: 'leadId',
- },
- constraints: false,
- });
-
- db.activities.belongsTo(db.deals, {
- as: 'deal',
- foreignKey: {
- name: 'dealId',
- },
- constraints: false,
- });
-
- db.activities.belongsTo(db.contacts, {
- as: 'contact',
- foreignKey: {
- name: 'contactId',
- },
- constraints: false,
- });
-
- db.activities.belongsTo(db.accounts, {
- as: 'account',
- foreignKey: {
- name: 'accountId',
- },
- constraints: false,
- });
-
-
-
- db.activities.hasMany(db.file, {
- as: 'attachments',
- foreignKey: 'belongsToId',
- constraints: false,
- scope: {
- belongsTo: db.activities.getTableName(),
- belongsToColumn: 'attachments',
- },
- });
-
-
- db.activities.belongsTo(db.users, {
- as: 'createdBy',
- });
-
- db.activities.belongsTo(db.users, {
- as: 'updatedBy',
- });
- };
-
-
-
- return activities;
-};
-
-
diff --git a/backend/src/db/models/contacts.js b/backend/src/db/models/contacts.js
deleted file mode 100644
index 4647498..0000000
--- a/backend/src/db/models/contacts.js
+++ /dev/null
@@ -1,186 +0,0 @@
-const config = require('../../config');
-const providers = config.providers;
-const crypto = require('crypto');
-const bcrypt = require('bcrypt');
-const moment = require('moment');
-
-module.exports = function(sequelize, DataTypes) {
- const contacts = sequelize.define(
- 'contacts',
- {
- id: {
- type: DataTypes.UUID,
- defaultValue: DataTypes.UUIDV4,
- primaryKey: true,
- },
-
-full_name: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-email: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-phone: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-job_title: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-contact_status: {
- type: DataTypes.ENUM,
-
-
-
- values: [
-
-"active",
-
-
-"do_not_contact",
-
-
-"bounced",
-
-
-"unsubscribed"
-
- ],
-
- },
-
-linkedin_url: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-notes: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-last_contacted_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-next_follow_up_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
- importHash: {
- type: DataTypes.STRING(255),
- allowNull: true,
- unique: true,
- },
- },
- {
- timestamps: true,
- paranoid: true,
- freezeTableName: true,
- },
- );
-
- contacts.associate = (db) => {
-
-
-/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
-
-
-
-
-
-
-
-
- db.contacts.hasMany(db.leads, {
- as: 'leads_primary_contact',
- foreignKey: {
- name: 'primary_contactId',
- },
- constraints: false,
- });
-
-
-
- db.contacts.hasMany(db.deals, {
- as: 'deals_primary_contact',
- foreignKey: {
- name: 'primary_contactId',
- },
- constraints: false,
- });
-
-
- db.contacts.hasMany(db.activities, {
- as: 'activities_contact',
- foreignKey: {
- name: 'contactId',
- },
- constraints: false,
- });
-
-
-
-//end loop
-
-
-
- db.contacts.belongsTo(db.accounts, {
- as: 'account',
- foreignKey: {
- name: 'accountId',
- },
- constraints: false,
- });
-
- db.contacts.belongsTo(db.users, {
- as: 'owner',
- foreignKey: {
- name: 'ownerId',
- },
- constraints: false,
- });
-
-
-
-
- db.contacts.belongsTo(db.users, {
- as: 'createdBy',
- });
-
- db.contacts.belongsTo(db.users, {
- as: 'updatedBy',
- });
- };
-
-
-
- return contacts;
-};
-
-
diff --git a/backend/src/db/models/deals.js b/backend/src/db/models/deals.js
deleted file mode 100644
index 0a86fd8..0000000
--- a/backend/src/db/models/deals.js
+++ /dev/null
@@ -1,198 +0,0 @@
-const config = require('../../config');
-const providers = config.providers;
-const crypto = require('crypto');
-const bcrypt = require('bcrypt');
-const moment = require('moment');
-
-module.exports = function(sequelize, DataTypes) {
- const deals = sequelize.define(
- 'deals',
- {
- id: {
- type: DataTypes.UUID,
- defaultValue: DataTypes.UUIDV4,
- primaryKey: true,
- },
-
-name: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-amount: {
- type: DataTypes.DECIMAL,
-
-
-
- },
-
-currency: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-expected_close_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-closed_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-deal_status: {
- type: DataTypes.ENUM,
-
-
-
- values: [
-
-"open",
-
-
-"won",
-
-
-"lost"
-
- ],
-
- },
-
-loss_reason: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-last_activity_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-next_follow_up_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-description: {
- type: DataTypes.TEXT,
-
-
-
- },
-
- importHash: {
- type: DataTypes.STRING(255),
- allowNull: true,
- unique: true,
- },
- },
- {
- timestamps: true,
- paranoid: true,
- freezeTableName: true,
- },
- );
-
- deals.associate = (db) => {
-
-
-/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
-
-
-
-
-
-
-
-
-
-
-
- db.deals.hasMany(db.activities, {
- as: 'activities_deal',
- foreignKey: {
- name: 'dealId',
- },
- constraints: false,
- });
-
-
-
-//end loop
-
-
-
- db.deals.belongsTo(db.pipeline_stages, {
- as: 'stage',
- foreignKey: {
- name: 'stageId',
- },
- constraints: false,
- });
-
- db.deals.belongsTo(db.users, {
- as: 'owner',
- foreignKey: {
- name: 'ownerId',
- },
- constraints: false,
- });
-
- db.deals.belongsTo(db.accounts, {
- as: 'account',
- foreignKey: {
- name: 'accountId',
- },
- constraints: false,
- });
-
- db.deals.belongsTo(db.contacts, {
- as: 'primary_contact',
- foreignKey: {
- name: 'primary_contactId',
- },
- constraints: false,
- });
-
- db.deals.belongsTo(db.leads, {
- as: 'originating_lead',
- foreignKey: {
- name: 'originating_leadId',
- },
- constraints: false,
- });
-
-
-
-
- db.deals.belongsTo(db.users, {
- as: 'createdBy',
- });
-
- db.deals.belongsTo(db.users, {
- as: 'updatedBy',
- });
- };
-
-
-
- return deals;
-};
-
-
diff --git a/backend/src/db/models/lead_sources.js b/backend/src/db/models/lead_sources.js
deleted file mode 100644
index 243a34e..0000000
--- a/backend/src/db/models/lead_sources.js
+++ /dev/null
@@ -1,100 +0,0 @@
-const config = require('../../config');
-const providers = config.providers;
-const crypto = require('crypto');
-const bcrypt = require('bcrypt');
-const moment = require('moment');
-
-module.exports = function(sequelize, DataTypes) {
- const lead_sources = sequelize.define(
- 'lead_sources',
- {
- id: {
- type: DataTypes.UUID,
- defaultValue: DataTypes.UUIDV4,
- primaryKey: true,
- },
-
-name: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-is_active: {
- type: DataTypes.BOOLEAN,
-
- allowNull: false,
- defaultValue: false,
-
-
-
- },
-
-description: {
- type: DataTypes.TEXT,
-
-
-
- },
-
- importHash: {
- type: DataTypes.STRING(255),
- allowNull: true,
- unique: true,
- },
- },
- {
- timestamps: true,
- paranoid: true,
- freezeTableName: true,
- },
- );
-
- lead_sources.associate = (db) => {
-
-
-/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
-
-
-
-
-
-
-
-
- db.lead_sources.hasMany(db.leads, {
- as: 'leads_source',
- foreignKey: {
- name: 'sourceId',
- },
- constraints: false,
- });
-
-
-
-
-
-
-//end loop
-
-
-
-
-
-
- db.lead_sources.belongsTo(db.users, {
- as: 'createdBy',
- });
-
- db.lead_sources.belongsTo(db.users, {
- as: 'updatedBy',
- });
- };
-
-
-
- return lead_sources;
-};
-
-
diff --git a/backend/src/db/models/leads.js b/backend/src/db/models/leads.js
deleted file mode 100644
index 069b54f..0000000
--- a/backend/src/db/models/leads.js
+++ /dev/null
@@ -1,209 +0,0 @@
-const config = require('../../config');
-const providers = config.providers;
-const crypto = require('crypto');
-const bcrypt = require('bcrypt');
-const moment = require('moment');
-
-module.exports = function(sequelize, DataTypes) {
- const leads = sequelize.define(
- 'leads',
- {
- id: {
- type: DataTypes.UUID,
- defaultValue: DataTypes.UUIDV4,
- primaryKey: true,
- },
-
-lead_name: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-company_name: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-email: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-phone: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-lead_status: {
- type: DataTypes.ENUM,
-
-
-
- values: [
-
-"new",
-
-
-"contacted",
-
-
-"qualified",
-
-
-"unqualified",
-
-
-"converted"
-
- ],
-
- },
-
-lead_rating: {
- type: DataTypes.ENUM,
-
-
-
- values: [
-
-"cold",
-
-
-"warm",
-
-
-"hot"
-
- ],
-
- },
-
-notes: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-last_contacted_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
-next_follow_up_at: {
- type: DataTypes.DATE,
-
-
-
- },
-
- importHash: {
- type: DataTypes.STRING(255),
- allowNull: true,
- unique: true,
- },
- },
- {
- timestamps: true,
- paranoid: true,
- freezeTableName: true,
- },
- );
-
- leads.associate = (db) => {
-
-
-/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
-
-
-
-
-
-
-
-
-
-
- db.leads.hasMany(db.deals, {
- as: 'deals_originating_lead',
- foreignKey: {
- name: 'originating_leadId',
- },
- constraints: false,
- });
-
-
- db.leads.hasMany(db.activities, {
- as: 'activities_lead',
- foreignKey: {
- name: 'leadId',
- },
- constraints: false,
- });
-
-
-
-//end loop
-
-
-
- db.leads.belongsTo(db.users, {
- as: 'owner',
- foreignKey: {
- name: 'ownerId',
- },
- constraints: false,
- });
-
- db.leads.belongsTo(db.lead_sources, {
- as: 'source',
- foreignKey: {
- name: 'sourceId',
- },
- constraints: false,
- });
-
- db.leads.belongsTo(db.accounts, {
- as: 'account',
- foreignKey: {
- name: 'accountId',
- },
- constraints: false,
- });
-
- db.leads.belongsTo(db.contacts, {
- as: 'primary_contact',
- foreignKey: {
- name: 'primary_contactId',
- },
- constraints: false,
- });
-
-
-
-
- db.leads.belongsTo(db.users, {
- as: 'createdBy',
- });
-
- db.leads.belongsTo(db.users, {
- as: 'updatedBy',
- });
- };
-
-
-
- return leads;
-};
-
-
diff --git a/backend/src/db/models/pipeline_stages.js b/backend/src/db/models/pipeline_stages.js
deleted file mode 100644
index a4da82f..0000000
--- a/backend/src/db/models/pipeline_stages.js
+++ /dev/null
@@ -1,127 +0,0 @@
-const config = require('../../config');
-const providers = config.providers;
-const crypto = require('crypto');
-const bcrypt = require('bcrypt');
-const moment = require('moment');
-
-module.exports = function(sequelize, DataTypes) {
- const pipeline_stages = sequelize.define(
- 'pipeline_stages',
- {
- id: {
- type: DataTypes.UUID,
- defaultValue: DataTypes.UUIDV4,
- primaryKey: true,
- },
-
-name: {
- type: DataTypes.TEXT,
-
-
-
- },
-
-sort_order: {
- type: DataTypes.INTEGER,
-
-
-
- },
-
-win_probability: {
- type: DataTypes.DECIMAL,
-
-
-
- },
-
-is_won: {
- type: DataTypes.BOOLEAN,
-
- allowNull: false,
- defaultValue: false,
-
-
-
- },
-
-is_lost: {
- type: DataTypes.BOOLEAN,
-
- allowNull: false,
- defaultValue: false,
-
-
-
- },
-
-is_active: {
- type: DataTypes.BOOLEAN,
-
- allowNull: false,
- defaultValue: false,
-
-
-
- },
-
- importHash: {
- type: DataTypes.STRING(255),
- allowNull: true,
- unique: true,
- },
- },
- {
- timestamps: true,
- paranoid: true,
- freezeTableName: true,
- },
- );
-
- pipeline_stages.associate = (db) => {
-
-
-/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
-
-
-
-
-
-
-
-
-
-
- db.pipeline_stages.hasMany(db.deals, {
- as: 'deals_stage',
- foreignKey: {
- name: 'stageId',
- },
- constraints: false,
- });
-
-
-
-
-//end loop
-
-
-
-
-
-
- db.pipeline_stages.belongsTo(db.users, {
- as: 'createdBy',
- });
-
- db.pipeline_stages.belongsTo(db.users, {
- as: 'updatedBy',
- });
- };
-
-
-
- return pipeline_stages;
-};
-
-
diff --git a/backend/src/routes/accounts.js b/backend/src/routes/accounts.js
deleted file mode 100644
index 3acf160..0000000
--- a/backend/src/routes/accounts.js
+++ /dev/null
@@ -1,454 +0,0 @@
-
-const express = require('express');
-
-const AccountsService = require('../services/accounts');
-const AccountsDBApi = require('../db/api/accounts');
-const wrapAsync = require('../helpers').wrapAsync;
-
-
-const router = express.Router();
-
-const { parse } = require('json2csv');
-
-
-const {
- checkCrudPermissions,
-} = require('../middlewares/check-permissions');
-
-router.use(checkCrudPermissions('accounts'));
-
-
-/**
- * @swagger
- * components:
- * schemas:
- * Accounts:
- * type: object
- * properties:
-
- * name:
- * type: string
- * default: name
- * domain:
- * type: string
- * default: domain
- * industry:
- * type: string
- * default: industry
- * phone:
- * type: string
- * default: phone
- * website:
- * type: string
- * default: website
- * address:
- * type: string
- * default: address
- * notes:
- * type: string
- * default: notes
-
- * employee_count:
- * type: integer
- * format: int64
-
- * annual_revenue:
- * type: integer
- * format: int64
-
- *
- */
-
-/**
- * @swagger
- * tags:
- * name: Accounts
- * description: The Accounts managing API
- */
-
-/**
-* @swagger
-* /api/accounts:
-* post:
-* security:
-* - bearerAuth: []
-* tags: [Accounts]
-* summary: Add new item
-* description: Add new item
-* requestBody:
-* required: true
-* content:
-* application/json:
-* schema:
-* properties:
-* data:
-* description: Data of the updated item
-* type: object
-* $ref: "#/components/schemas/Accounts"
-* responses:
-* 200:
-* description: The item was successfully added
-* content:
-* application/json:
-* schema:
-* $ref: "#/components/schemas/Accounts"
-* 401:
-* $ref: "#/components/responses/UnauthorizedError"
-* 405:
-* description: Invalid input data
-* 500:
-* description: Some server error
-*/
-router.post('/', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await AccountsService.create(req.body.data, req.currentUser, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/budgets/bulk-import:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Accounts]
- * summary: Bulk import items
- * description: Bulk import items
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * data:
- * description: Data of the updated items
- * type: array
- * items:
- * $ref: "#/components/schemas/Accounts"
- * responses:
- * 200:
- * description: The items were successfully imported
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Accounts"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 405:
- * description: Invalid input data
- * 500:
- * description: Some server error
- *
- */
-router.post('/bulk-import', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await AccountsService.bulkImport(req, res, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/accounts/{id}:
- * put:
- * security:
- * - bearerAuth: []
- * tags: [Accounts]
- * summary: Update the data of the selected item
- * description: Update the data of the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to update
- * required: true
- * schema:
- * type: string
- * requestBody:
- * description: Set new item data
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * id:
- * description: ID of the updated item
- * type: string
- * data:
- * description: Data of the updated item
- * type: object
- * $ref: "#/components/schemas/Accounts"
- * required:
- * - id
- * responses:
- * 200:
- * description: The item data was successfully updated
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Accounts"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.put('/:id', wrapAsync(async (req, res) => {
- await AccountsService.update(req.body.data, req.body.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/accounts/{id}:
- * delete:
- * security:
- * - bearerAuth: []
- * tags: [Accounts]
- * summary: Delete the selected item
- * description: Delete the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to delete
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: The item was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Accounts"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.delete('/:id', wrapAsync(async (req, res) => {
- await AccountsService.remove(req.params.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/accounts/deleteByIds:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Accounts]
- * summary: Delete the selected item list
- * description: Delete the selected item list
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * ids:
- * description: IDs of the updated items
- * type: array
- * responses:
- * 200:
- * description: The items was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Accounts"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Items not found
- * 500:
- * description: Some server error
- */
-router.post('/deleteByIds', wrapAsync(async (req, res) => {
- await AccountsService.deleteByIds(req.body.data, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
- }));
-
-/**
- * @swagger
- * /api/accounts:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Accounts]
- * summary: Get all accounts
- * description: Get all accounts
- * responses:
- * 200:
- * description: Accounts list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Accounts"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
-*/
-router.get('/', wrapAsync(async (req, res) => {
- const filetype = req.query.filetype
-
- const currentUser = req.currentUser;
- const payload = await AccountsDBApi.findAll(
- req.query, { currentUser }
- );
- if (filetype && filetype === 'csv') {
- const fields = ['id','name','domain','industry','phone','website','address','notes',
- 'employee_count',
- 'annual_revenue',
- 'last_contacted_at','next_follow_up_at',
- ];
- const opts = { fields };
- try {
- const csv = parse(payload.rows, opts);
- res.status(200).attachment(csv);
- res.send(csv)
-
- } catch (err) {
- console.error(err);
- }
- } else {
- res.status(200).send(payload);
- }
-
-}));
-
-/**
- * @swagger
- * /api/accounts/count:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Accounts]
- * summary: Count all accounts
- * description: Count all accounts
- * responses:
- * 200:
- * description: Accounts count successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Accounts"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/count', wrapAsync(async (req, res) => {
-
- const currentUser = req.currentUser;
- const payload = await AccountsDBApi.findAll(
- req.query,
- null,
- { countOnly: true, currentUser }
- );
-
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/accounts/autocomplete:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Accounts]
- * summary: Find all accounts that match search criteria
- * description: Find all accounts that match search criteria
- * responses:
- * 200:
- * description: Accounts list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Accounts"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/autocomplete', async (req, res) => {
-
- const payload = await AccountsDBApi.findAllAutocomplete(
- req.query.query,
- req.query.limit,
- req.query.offset,
-
- );
-
- res.status(200).send(payload);
-});
-
-/**
- * @swagger
- * /api/accounts/{id}:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Accounts]
- * summary: Get selected item
- * description: Get selected item
- * parameters:
- * - in: path
- * name: id
- * description: ID of item to get
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: Selected item successfully received
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Accounts"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.get('/:id', wrapAsync(async (req, res) => {
- const payload = await AccountsDBApi.findBy(
- { id: req.params.id },
- );
-
-
-
- res.status(200).send(payload);
-}));
-
-router.use('/', require('../helpers').commonErrorHandler);
-
-module.exports = router;
diff --git a/backend/src/routes/activities.js b/backend/src/routes/activities.js
deleted file mode 100644
index 603f1a9..0000000
--- a/backend/src/routes/activities.js
+++ /dev/null
@@ -1,435 +0,0 @@
-
-const express = require('express');
-
-const ActivitiesService = require('../services/activities');
-const ActivitiesDBApi = require('../db/api/activities');
-const wrapAsync = require('../helpers').wrapAsync;
-
-
-const router = express.Router();
-
-const { parse } = require('json2csv');
-
-
-const {
- checkCrudPermissions,
-} = require('../middlewares/check-permissions');
-
-router.use(checkCrudPermissions('activities'));
-
-
-/**
- * @swagger
- * components:
- * schemas:
- * Activities:
- * type: object
- * properties:
-
- * subject:
- * type: string
- * default: subject
- * details:
- * type: string
- * default: details
-
-
-
- *
- *
- *
- */
-
-/**
- * @swagger
- * tags:
- * name: Activities
- * description: The Activities managing API
- */
-
-/**
-* @swagger
-* /api/activities:
-* post:
-* security:
-* - bearerAuth: []
-* tags: [Activities]
-* summary: Add new item
-* description: Add new item
-* requestBody:
-* required: true
-* content:
-* application/json:
-* schema:
-* properties:
-* data:
-* description: Data of the updated item
-* type: object
-* $ref: "#/components/schemas/Activities"
-* responses:
-* 200:
-* description: The item was successfully added
-* content:
-* application/json:
-* schema:
-* $ref: "#/components/schemas/Activities"
-* 401:
-* $ref: "#/components/responses/UnauthorizedError"
-* 405:
-* description: Invalid input data
-* 500:
-* description: Some server error
-*/
-router.post('/', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await ActivitiesService.create(req.body.data, req.currentUser, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/budgets/bulk-import:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Activities]
- * summary: Bulk import items
- * description: Bulk import items
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * data:
- * description: Data of the updated items
- * type: array
- * items:
- * $ref: "#/components/schemas/Activities"
- * responses:
- * 200:
- * description: The items were successfully imported
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Activities"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 405:
- * description: Invalid input data
- * 500:
- * description: Some server error
- *
- */
-router.post('/bulk-import', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await ActivitiesService.bulkImport(req, res, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/activities/{id}:
- * put:
- * security:
- * - bearerAuth: []
- * tags: [Activities]
- * summary: Update the data of the selected item
- * description: Update the data of the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to update
- * required: true
- * schema:
- * type: string
- * requestBody:
- * description: Set new item data
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * id:
- * description: ID of the updated item
- * type: string
- * data:
- * description: Data of the updated item
- * type: object
- * $ref: "#/components/schemas/Activities"
- * required:
- * - id
- * responses:
- * 200:
- * description: The item data was successfully updated
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Activities"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.put('/:id', wrapAsync(async (req, res) => {
- await ActivitiesService.update(req.body.data, req.body.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/activities/{id}:
- * delete:
- * security:
- * - bearerAuth: []
- * tags: [Activities]
- * summary: Delete the selected item
- * description: Delete the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to delete
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: The item was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Activities"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.delete('/:id', wrapAsync(async (req, res) => {
- await ActivitiesService.remove(req.params.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/activities/deleteByIds:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Activities]
- * summary: Delete the selected item list
- * description: Delete the selected item list
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * ids:
- * description: IDs of the updated items
- * type: array
- * responses:
- * 200:
- * description: The items was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Activities"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Items not found
- * 500:
- * description: Some server error
- */
-router.post('/deleteByIds', wrapAsync(async (req, res) => {
- await ActivitiesService.deleteByIds(req.body.data, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
- }));
-
-/**
- * @swagger
- * /api/activities:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Activities]
- * summary: Get all activities
- * description: Get all activities
- * responses:
- * 200:
- * description: Activities list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Activities"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
-*/
-router.get('/', wrapAsync(async (req, res) => {
- const filetype = req.query.filetype
-
- const currentUser = req.currentUser;
- const payload = await ActivitiesDBApi.findAll(
- req.query, { currentUser }
- );
- if (filetype && filetype === 'csv') {
- const fields = ['id','subject','details',
-
-
- 'activity_at','due_at','completed_at',
- ];
- const opts = { fields };
- try {
- const csv = parse(payload.rows, opts);
- res.status(200).attachment(csv);
- res.send(csv)
-
- } catch (err) {
- console.error(err);
- }
- } else {
- res.status(200).send(payload);
- }
-
-}));
-
-/**
- * @swagger
- * /api/activities/count:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Activities]
- * summary: Count all activities
- * description: Count all activities
- * responses:
- * 200:
- * description: Activities count successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Activities"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/count', wrapAsync(async (req, res) => {
-
- const currentUser = req.currentUser;
- const payload = await ActivitiesDBApi.findAll(
- req.query,
- null,
- { countOnly: true, currentUser }
- );
-
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/activities/autocomplete:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Activities]
- * summary: Find all activities that match search criteria
- * description: Find all activities that match search criteria
- * responses:
- * 200:
- * description: Activities list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Activities"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/autocomplete', async (req, res) => {
-
- const payload = await ActivitiesDBApi.findAllAutocomplete(
- req.query.query,
- req.query.limit,
- req.query.offset,
-
- );
-
- res.status(200).send(payload);
-});
-
-/**
- * @swagger
- * /api/activities/{id}:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Activities]
- * summary: Get selected item
- * description: Get selected item
- * parameters:
- * - in: path
- * name: id
- * description: ID of item to get
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: Selected item successfully received
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Activities"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.get('/:id', wrapAsync(async (req, res) => {
- const payload = await ActivitiesDBApi.findBy(
- { id: req.params.id },
- );
-
-
-
- res.status(200).send(payload);
-}));
-
-router.use('/', require('../helpers').commonErrorHandler);
-
-module.exports = router;
diff --git a/backend/src/routes/contacts.js b/backend/src/routes/contacts.js
deleted file mode 100644
index 3285671..0000000
--- a/backend/src/routes/contacts.js
+++ /dev/null
@@ -1,445 +0,0 @@
-
-const express = require('express');
-
-const ContactsService = require('../services/contacts');
-const ContactsDBApi = require('../db/api/contacts');
-const wrapAsync = require('../helpers').wrapAsync;
-
-
-const router = express.Router();
-
-const { parse } = require('json2csv');
-
-
-const {
- checkCrudPermissions,
-} = require('../middlewares/check-permissions');
-
-router.use(checkCrudPermissions('contacts'));
-
-
-/**
- * @swagger
- * components:
- * schemas:
- * Contacts:
- * type: object
- * properties:
-
- * full_name:
- * type: string
- * default: full_name
- * email:
- * type: string
- * default: email
- * phone:
- * type: string
- * default: phone
- * job_title:
- * type: string
- * default: job_title
- * linkedin_url:
- * type: string
- * default: linkedin_url
- * notes:
- * type: string
- * default: notes
-
-
-
- *
- */
-
-/**
- * @swagger
- * tags:
- * name: Contacts
- * description: The Contacts managing API
- */
-
-/**
-* @swagger
-* /api/contacts:
-* post:
-* security:
-* - bearerAuth: []
-* tags: [Contacts]
-* summary: Add new item
-* description: Add new item
-* requestBody:
-* required: true
-* content:
-* application/json:
-* schema:
-* properties:
-* data:
-* description: Data of the updated item
-* type: object
-* $ref: "#/components/schemas/Contacts"
-* responses:
-* 200:
-* description: The item was successfully added
-* content:
-* application/json:
-* schema:
-* $ref: "#/components/schemas/Contacts"
-* 401:
-* $ref: "#/components/responses/UnauthorizedError"
-* 405:
-* description: Invalid input data
-* 500:
-* description: Some server error
-*/
-router.post('/', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await ContactsService.create(req.body.data, req.currentUser, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/budgets/bulk-import:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Contacts]
- * summary: Bulk import items
- * description: Bulk import items
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * data:
- * description: Data of the updated items
- * type: array
- * items:
- * $ref: "#/components/schemas/Contacts"
- * responses:
- * 200:
- * description: The items were successfully imported
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Contacts"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 405:
- * description: Invalid input data
- * 500:
- * description: Some server error
- *
- */
-router.post('/bulk-import', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await ContactsService.bulkImport(req, res, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/contacts/{id}:
- * put:
- * security:
- * - bearerAuth: []
- * tags: [Contacts]
- * summary: Update the data of the selected item
- * description: Update the data of the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to update
- * required: true
- * schema:
- * type: string
- * requestBody:
- * description: Set new item data
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * id:
- * description: ID of the updated item
- * type: string
- * data:
- * description: Data of the updated item
- * type: object
- * $ref: "#/components/schemas/Contacts"
- * required:
- * - id
- * responses:
- * 200:
- * description: The item data was successfully updated
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Contacts"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.put('/:id', wrapAsync(async (req, res) => {
- await ContactsService.update(req.body.data, req.body.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/contacts/{id}:
- * delete:
- * security:
- * - bearerAuth: []
- * tags: [Contacts]
- * summary: Delete the selected item
- * description: Delete the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to delete
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: The item was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Contacts"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.delete('/:id', wrapAsync(async (req, res) => {
- await ContactsService.remove(req.params.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/contacts/deleteByIds:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Contacts]
- * summary: Delete the selected item list
- * description: Delete the selected item list
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * ids:
- * description: IDs of the updated items
- * type: array
- * responses:
- * 200:
- * description: The items was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Contacts"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Items not found
- * 500:
- * description: Some server error
- */
-router.post('/deleteByIds', wrapAsync(async (req, res) => {
- await ContactsService.deleteByIds(req.body.data, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
- }));
-
-/**
- * @swagger
- * /api/contacts:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Contacts]
- * summary: Get all contacts
- * description: Get all contacts
- * responses:
- * 200:
- * description: Contacts list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Contacts"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
-*/
-router.get('/', wrapAsync(async (req, res) => {
- const filetype = req.query.filetype
-
- const currentUser = req.currentUser;
- const payload = await ContactsDBApi.findAll(
- req.query, { currentUser }
- );
- if (filetype && filetype === 'csv') {
- const fields = ['id','full_name','email','phone','job_title','linkedin_url','notes',
-
-
- 'last_contacted_at','next_follow_up_at',
- ];
- const opts = { fields };
- try {
- const csv = parse(payload.rows, opts);
- res.status(200).attachment(csv);
- res.send(csv)
-
- } catch (err) {
- console.error(err);
- }
- } else {
- res.status(200).send(payload);
- }
-
-}));
-
-/**
- * @swagger
- * /api/contacts/count:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Contacts]
- * summary: Count all contacts
- * description: Count all contacts
- * responses:
- * 200:
- * description: Contacts count successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Contacts"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/count', wrapAsync(async (req, res) => {
-
- const currentUser = req.currentUser;
- const payload = await ContactsDBApi.findAll(
- req.query,
- null,
- { countOnly: true, currentUser }
- );
-
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/contacts/autocomplete:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Contacts]
- * summary: Find all contacts that match search criteria
- * description: Find all contacts that match search criteria
- * responses:
- * 200:
- * description: Contacts list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Contacts"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/autocomplete', async (req, res) => {
-
- const payload = await ContactsDBApi.findAllAutocomplete(
- req.query.query,
- req.query.limit,
- req.query.offset,
-
- );
-
- res.status(200).send(payload);
-});
-
-/**
- * @swagger
- * /api/contacts/{id}:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Contacts]
- * summary: Get selected item
- * description: Get selected item
- * parameters:
- * - in: path
- * name: id
- * description: ID of item to get
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: Selected item successfully received
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Contacts"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.get('/:id', wrapAsync(async (req, res) => {
- const payload = await ContactsDBApi.findBy(
- { id: req.params.id },
- );
-
-
-
- res.status(200).send(payload);
-}));
-
-router.use('/', require('../helpers').commonErrorHandler);
-
-module.exports = router;
diff --git a/backend/src/routes/deals.js b/backend/src/routes/deals.js
deleted file mode 100644
index a35e517..0000000
--- a/backend/src/routes/deals.js
+++ /dev/null
@@ -1,442 +0,0 @@
-
-const express = require('express');
-
-const DealsService = require('../services/deals');
-const DealsDBApi = require('../db/api/deals');
-const wrapAsync = require('../helpers').wrapAsync;
-
-
-const router = express.Router();
-
-const { parse } = require('json2csv');
-
-
-const {
- checkCrudPermissions,
-} = require('../middlewares/check-permissions');
-
-router.use(checkCrudPermissions('deals'));
-
-
-/**
- * @swagger
- * components:
- * schemas:
- * Deals:
- * type: object
- * properties:
-
- * name:
- * type: string
- * default: name
- * currency:
- * type: string
- * default: currency
- * loss_reason:
- * type: string
- * default: loss_reason
- * description:
- * type: string
- * default: description
-
-
- * amount:
- * type: integer
- * format: int64
-
- *
- */
-
-/**
- * @swagger
- * tags:
- * name: Deals
- * description: The Deals managing API
- */
-
-/**
-* @swagger
-* /api/deals:
-* post:
-* security:
-* - bearerAuth: []
-* tags: [Deals]
-* summary: Add new item
-* description: Add new item
-* requestBody:
-* required: true
-* content:
-* application/json:
-* schema:
-* properties:
-* data:
-* description: Data of the updated item
-* type: object
-* $ref: "#/components/schemas/Deals"
-* responses:
-* 200:
-* description: The item was successfully added
-* content:
-* application/json:
-* schema:
-* $ref: "#/components/schemas/Deals"
-* 401:
-* $ref: "#/components/responses/UnauthorizedError"
-* 405:
-* description: Invalid input data
-* 500:
-* description: Some server error
-*/
-router.post('/', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await DealsService.create(req.body.data, req.currentUser, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/budgets/bulk-import:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Deals]
- * summary: Bulk import items
- * description: Bulk import items
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * data:
- * description: Data of the updated items
- * type: array
- * items:
- * $ref: "#/components/schemas/Deals"
- * responses:
- * 200:
- * description: The items were successfully imported
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Deals"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 405:
- * description: Invalid input data
- * 500:
- * description: Some server error
- *
- */
-router.post('/bulk-import', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await DealsService.bulkImport(req, res, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/deals/{id}:
- * put:
- * security:
- * - bearerAuth: []
- * tags: [Deals]
- * summary: Update the data of the selected item
- * description: Update the data of the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to update
- * required: true
- * schema:
- * type: string
- * requestBody:
- * description: Set new item data
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * id:
- * description: ID of the updated item
- * type: string
- * data:
- * description: Data of the updated item
- * type: object
- * $ref: "#/components/schemas/Deals"
- * required:
- * - id
- * responses:
- * 200:
- * description: The item data was successfully updated
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Deals"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.put('/:id', wrapAsync(async (req, res) => {
- await DealsService.update(req.body.data, req.body.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/deals/{id}:
- * delete:
- * security:
- * - bearerAuth: []
- * tags: [Deals]
- * summary: Delete the selected item
- * description: Delete the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to delete
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: The item was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Deals"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.delete('/:id', wrapAsync(async (req, res) => {
- await DealsService.remove(req.params.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/deals/deleteByIds:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Deals]
- * summary: Delete the selected item list
- * description: Delete the selected item list
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * ids:
- * description: IDs of the updated items
- * type: array
- * responses:
- * 200:
- * description: The items was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Deals"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Items not found
- * 500:
- * description: Some server error
- */
-router.post('/deleteByIds', wrapAsync(async (req, res) => {
- await DealsService.deleteByIds(req.body.data, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
- }));
-
-/**
- * @swagger
- * /api/deals:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Deals]
- * summary: Get all deals
- * description: Get all deals
- * responses:
- * 200:
- * description: Deals list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Deals"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
-*/
-router.get('/', wrapAsync(async (req, res) => {
- const filetype = req.query.filetype
-
- const currentUser = req.currentUser;
- const payload = await DealsDBApi.findAll(
- req.query, { currentUser }
- );
- if (filetype && filetype === 'csv') {
- const fields = ['id','name','currency','loss_reason','description',
-
- 'amount',
- 'expected_close_at','closed_at','last_activity_at','next_follow_up_at',
- ];
- const opts = { fields };
- try {
- const csv = parse(payload.rows, opts);
- res.status(200).attachment(csv);
- res.send(csv)
-
- } catch (err) {
- console.error(err);
- }
- } else {
- res.status(200).send(payload);
- }
-
-}));
-
-/**
- * @swagger
- * /api/deals/count:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Deals]
- * summary: Count all deals
- * description: Count all deals
- * responses:
- * 200:
- * description: Deals count successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Deals"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/count', wrapAsync(async (req, res) => {
-
- const currentUser = req.currentUser;
- const payload = await DealsDBApi.findAll(
- req.query,
- null,
- { countOnly: true, currentUser }
- );
-
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/deals/autocomplete:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Deals]
- * summary: Find all deals that match search criteria
- * description: Find all deals that match search criteria
- * responses:
- * 200:
- * description: Deals list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Deals"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/autocomplete', async (req, res) => {
-
- const payload = await DealsDBApi.findAllAutocomplete(
- req.query.query,
- req.query.limit,
- req.query.offset,
-
- );
-
- res.status(200).send(payload);
-});
-
-/**
- * @swagger
- * /api/deals/{id}:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Deals]
- * summary: Get selected item
- * description: Get selected item
- * parameters:
- * - in: path
- * name: id
- * description: ID of item to get
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: Selected item successfully received
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Deals"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.get('/:id', wrapAsync(async (req, res) => {
- const payload = await DealsDBApi.findBy(
- { id: req.params.id },
- );
-
-
-
- res.status(200).send(payload);
-}));
-
-router.use('/', require('../helpers').commonErrorHandler);
-
-module.exports = router;
diff --git a/backend/src/routes/lead_sources.js b/backend/src/routes/lead_sources.js
deleted file mode 100644
index 8143653..0000000
--- a/backend/src/routes/lead_sources.js
+++ /dev/null
@@ -1,432 +0,0 @@
-
-const express = require('express');
-
-const Lead_sourcesService = require('../services/lead_sources');
-const Lead_sourcesDBApi = require('../db/api/lead_sources');
-const wrapAsync = require('../helpers').wrapAsync;
-
-
-const router = express.Router();
-
-const { parse } = require('json2csv');
-
-
-const {
- checkCrudPermissions,
-} = require('../middlewares/check-permissions');
-
-router.use(checkCrudPermissions('lead_sources'));
-
-
-/**
- * @swagger
- * components:
- * schemas:
- * Lead_sources:
- * type: object
- * properties:
-
- * name:
- * type: string
- * default: name
- * description:
- * type: string
- * default: description
-
-
-
- */
-
-/**
- * @swagger
- * tags:
- * name: Lead_sources
- * description: The Lead_sources managing API
- */
-
-/**
-* @swagger
-* /api/lead_sources:
-* post:
-* security:
-* - bearerAuth: []
-* tags: [Lead_sources]
-* summary: Add new item
-* description: Add new item
-* requestBody:
-* required: true
-* content:
-* application/json:
-* schema:
-* properties:
-* data:
-* description: Data of the updated item
-* type: object
-* $ref: "#/components/schemas/Lead_sources"
-* responses:
-* 200:
-* description: The item was successfully added
-* content:
-* application/json:
-* schema:
-* $ref: "#/components/schemas/Lead_sources"
-* 401:
-* $ref: "#/components/responses/UnauthorizedError"
-* 405:
-* description: Invalid input data
-* 500:
-* description: Some server error
-*/
-router.post('/', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await Lead_sourcesService.create(req.body.data, req.currentUser, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/budgets/bulk-import:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Lead_sources]
- * summary: Bulk import items
- * description: Bulk import items
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * data:
- * description: Data of the updated items
- * type: array
- * items:
- * $ref: "#/components/schemas/Lead_sources"
- * responses:
- * 200:
- * description: The items were successfully imported
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Lead_sources"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 405:
- * description: Invalid input data
- * 500:
- * description: Some server error
- *
- */
-router.post('/bulk-import', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await Lead_sourcesService.bulkImport(req, res, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/lead_sources/{id}:
- * put:
- * security:
- * - bearerAuth: []
- * tags: [Lead_sources]
- * summary: Update the data of the selected item
- * description: Update the data of the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to update
- * required: true
- * schema:
- * type: string
- * requestBody:
- * description: Set new item data
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * id:
- * description: ID of the updated item
- * type: string
- * data:
- * description: Data of the updated item
- * type: object
- * $ref: "#/components/schemas/Lead_sources"
- * required:
- * - id
- * responses:
- * 200:
- * description: The item data was successfully updated
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Lead_sources"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.put('/:id', wrapAsync(async (req, res) => {
- await Lead_sourcesService.update(req.body.data, req.body.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/lead_sources/{id}:
- * delete:
- * security:
- * - bearerAuth: []
- * tags: [Lead_sources]
- * summary: Delete the selected item
- * description: Delete the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to delete
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: The item was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Lead_sources"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.delete('/:id', wrapAsync(async (req, res) => {
- await Lead_sourcesService.remove(req.params.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/lead_sources/deleteByIds:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Lead_sources]
- * summary: Delete the selected item list
- * description: Delete the selected item list
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * ids:
- * description: IDs of the updated items
- * type: array
- * responses:
- * 200:
- * description: The items was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Lead_sources"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Items not found
- * 500:
- * description: Some server error
- */
-router.post('/deleteByIds', wrapAsync(async (req, res) => {
- await Lead_sourcesService.deleteByIds(req.body.data, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
- }));
-
-/**
- * @swagger
- * /api/lead_sources:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Lead_sources]
- * summary: Get all lead_sources
- * description: Get all lead_sources
- * responses:
- * 200:
- * description: Lead_sources list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Lead_sources"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
-*/
-router.get('/', wrapAsync(async (req, res) => {
- const filetype = req.query.filetype
-
- const currentUser = req.currentUser;
- const payload = await Lead_sourcesDBApi.findAll(
- req.query, { currentUser }
- );
- if (filetype && filetype === 'csv') {
- const fields = ['id','name','description',
-
-
-
- ];
- const opts = { fields };
- try {
- const csv = parse(payload.rows, opts);
- res.status(200).attachment(csv);
- res.send(csv)
-
- } catch (err) {
- console.error(err);
- }
- } else {
- res.status(200).send(payload);
- }
-
-}));
-
-/**
- * @swagger
- * /api/lead_sources/count:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Lead_sources]
- * summary: Count all lead_sources
- * description: Count all lead_sources
- * responses:
- * 200:
- * description: Lead_sources count successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Lead_sources"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/count', wrapAsync(async (req, res) => {
-
- const currentUser = req.currentUser;
- const payload = await Lead_sourcesDBApi.findAll(
- req.query,
- null,
- { countOnly: true, currentUser }
- );
-
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/lead_sources/autocomplete:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Lead_sources]
- * summary: Find all lead_sources that match search criteria
- * description: Find all lead_sources that match search criteria
- * responses:
- * 200:
- * description: Lead_sources list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Lead_sources"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/autocomplete', async (req, res) => {
-
- const payload = await Lead_sourcesDBApi.findAllAutocomplete(
- req.query.query,
- req.query.limit,
- req.query.offset,
-
- );
-
- res.status(200).send(payload);
-});
-
-/**
- * @swagger
- * /api/lead_sources/{id}:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Lead_sources]
- * summary: Get selected item
- * description: Get selected item
- * parameters:
- * - in: path
- * name: id
- * description: ID of item to get
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: Selected item successfully received
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Lead_sources"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.get('/:id', wrapAsync(async (req, res) => {
- const payload = await Lead_sourcesDBApi.findBy(
- { id: req.params.id },
- );
-
-
-
- res.status(200).send(payload);
-}));
-
-router.use('/', require('../helpers').commonErrorHandler);
-
-module.exports = router;
diff --git a/backend/src/routes/leads.js b/backend/src/routes/leads.js
deleted file mode 100644
index 9bc62ce..0000000
--- a/backend/src/routes/leads.js
+++ /dev/null
@@ -1,443 +0,0 @@
-
-const express = require('express');
-
-const LeadsService = require('../services/leads');
-const LeadsDBApi = require('../db/api/leads');
-const wrapAsync = require('../helpers').wrapAsync;
-
-
-const router = express.Router();
-
-const { parse } = require('json2csv');
-
-
-const {
- checkCrudPermissions,
-} = require('../middlewares/check-permissions');
-
-router.use(checkCrudPermissions('leads'));
-
-
-/**
- * @swagger
- * components:
- * schemas:
- * Leads:
- * type: object
- * properties:
-
- * lead_name:
- * type: string
- * default: lead_name
- * company_name:
- * type: string
- * default: company_name
- * email:
- * type: string
- * default: email
- * phone:
- * type: string
- * default: phone
- * notes:
- * type: string
- * default: notes
-
-
-
- *
- *
- */
-
-/**
- * @swagger
- * tags:
- * name: Leads
- * description: The Leads managing API
- */
-
-/**
-* @swagger
-* /api/leads:
-* post:
-* security:
-* - bearerAuth: []
-* tags: [Leads]
-* summary: Add new item
-* description: Add new item
-* requestBody:
-* required: true
-* content:
-* application/json:
-* schema:
-* properties:
-* data:
-* description: Data of the updated item
-* type: object
-* $ref: "#/components/schemas/Leads"
-* responses:
-* 200:
-* description: The item was successfully added
-* content:
-* application/json:
-* schema:
-* $ref: "#/components/schemas/Leads"
-* 401:
-* $ref: "#/components/responses/UnauthorizedError"
-* 405:
-* description: Invalid input data
-* 500:
-* description: Some server error
-*/
-router.post('/', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await LeadsService.create(req.body.data, req.currentUser, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/budgets/bulk-import:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Leads]
- * summary: Bulk import items
- * description: Bulk import items
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * data:
- * description: Data of the updated items
- * type: array
- * items:
- * $ref: "#/components/schemas/Leads"
- * responses:
- * 200:
- * description: The items were successfully imported
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Leads"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 405:
- * description: Invalid input data
- * 500:
- * description: Some server error
- *
- */
-router.post('/bulk-import', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await LeadsService.bulkImport(req, res, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/leads/{id}:
- * put:
- * security:
- * - bearerAuth: []
- * tags: [Leads]
- * summary: Update the data of the selected item
- * description: Update the data of the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to update
- * required: true
- * schema:
- * type: string
- * requestBody:
- * description: Set new item data
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * id:
- * description: ID of the updated item
- * type: string
- * data:
- * description: Data of the updated item
- * type: object
- * $ref: "#/components/schemas/Leads"
- * required:
- * - id
- * responses:
- * 200:
- * description: The item data was successfully updated
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Leads"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.put('/:id', wrapAsync(async (req, res) => {
- await LeadsService.update(req.body.data, req.body.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/leads/{id}:
- * delete:
- * security:
- * - bearerAuth: []
- * tags: [Leads]
- * summary: Delete the selected item
- * description: Delete the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to delete
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: The item was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Leads"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.delete('/:id', wrapAsync(async (req, res) => {
- await LeadsService.remove(req.params.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/leads/deleteByIds:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Leads]
- * summary: Delete the selected item list
- * description: Delete the selected item list
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * ids:
- * description: IDs of the updated items
- * type: array
- * responses:
- * 200:
- * description: The items was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Leads"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Items not found
- * 500:
- * description: Some server error
- */
-router.post('/deleteByIds', wrapAsync(async (req, res) => {
- await LeadsService.deleteByIds(req.body.data, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
- }));
-
-/**
- * @swagger
- * /api/leads:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Leads]
- * summary: Get all leads
- * description: Get all leads
- * responses:
- * 200:
- * description: Leads list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Leads"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
-*/
-router.get('/', wrapAsync(async (req, res) => {
- const filetype = req.query.filetype
-
- const currentUser = req.currentUser;
- const payload = await LeadsDBApi.findAll(
- req.query, { currentUser }
- );
- if (filetype && filetype === 'csv') {
- const fields = ['id','lead_name','company_name','email','phone','notes',
-
-
- 'last_contacted_at','next_follow_up_at',
- ];
- const opts = { fields };
- try {
- const csv = parse(payload.rows, opts);
- res.status(200).attachment(csv);
- res.send(csv)
-
- } catch (err) {
- console.error(err);
- }
- } else {
- res.status(200).send(payload);
- }
-
-}));
-
-/**
- * @swagger
- * /api/leads/count:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Leads]
- * summary: Count all leads
- * description: Count all leads
- * responses:
- * 200:
- * description: Leads count successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Leads"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/count', wrapAsync(async (req, res) => {
-
- const currentUser = req.currentUser;
- const payload = await LeadsDBApi.findAll(
- req.query,
- null,
- { countOnly: true, currentUser }
- );
-
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/leads/autocomplete:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Leads]
- * summary: Find all leads that match search criteria
- * description: Find all leads that match search criteria
- * responses:
- * 200:
- * description: Leads list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Leads"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/autocomplete', async (req, res) => {
-
- const payload = await LeadsDBApi.findAllAutocomplete(
- req.query.query,
- req.query.limit,
- req.query.offset,
-
- );
-
- res.status(200).send(payload);
-});
-
-/**
- * @swagger
- * /api/leads/{id}:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Leads]
- * summary: Get selected item
- * description: Get selected item
- * parameters:
- * - in: path
- * name: id
- * description: ID of item to get
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: Selected item successfully received
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Leads"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.get('/:id', wrapAsync(async (req, res) => {
- const payload = await LeadsDBApi.findBy(
- { id: req.params.id },
- );
-
-
-
- res.status(200).send(payload);
-}));
-
-router.use('/', require('../helpers').commonErrorHandler);
-
-module.exports = router;
diff --git a/backend/src/routes/pipeline_stages.js b/backend/src/routes/pipeline_stages.js
deleted file mode 100644
index 0eff342..0000000
--- a/backend/src/routes/pipeline_stages.js
+++ /dev/null
@@ -1,435 +0,0 @@
-
-const express = require('express');
-
-const Pipeline_stagesService = require('../services/pipeline_stages');
-const Pipeline_stagesDBApi = require('../db/api/pipeline_stages');
-const wrapAsync = require('../helpers').wrapAsync;
-
-
-const router = express.Router();
-
-const { parse } = require('json2csv');
-
-
-const {
- checkCrudPermissions,
-} = require('../middlewares/check-permissions');
-
-router.use(checkCrudPermissions('pipeline_stages'));
-
-
-/**
- * @swagger
- * components:
- * schemas:
- * Pipeline_stages:
- * type: object
- * properties:
-
- * name:
- * type: string
- * default: name
-
- * sort_order:
- * type: integer
- * format: int64
-
- * win_probability:
- * type: integer
- * format: int64
-
- */
-
-/**
- * @swagger
- * tags:
- * name: Pipeline_stages
- * description: The Pipeline_stages managing API
- */
-
-/**
-* @swagger
-* /api/pipeline_stages:
-* post:
-* security:
-* - bearerAuth: []
-* tags: [Pipeline_stages]
-* summary: Add new item
-* description: Add new item
-* requestBody:
-* required: true
-* content:
-* application/json:
-* schema:
-* properties:
-* data:
-* description: Data of the updated item
-* type: object
-* $ref: "#/components/schemas/Pipeline_stages"
-* responses:
-* 200:
-* description: The item was successfully added
-* content:
-* application/json:
-* schema:
-* $ref: "#/components/schemas/Pipeline_stages"
-* 401:
-* $ref: "#/components/responses/UnauthorizedError"
-* 405:
-* description: Invalid input data
-* 500:
-* description: Some server error
-*/
-router.post('/', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await Pipeline_stagesService.create(req.body.data, req.currentUser, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/budgets/bulk-import:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Pipeline_stages]
- * summary: Bulk import items
- * description: Bulk import items
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * data:
- * description: Data of the updated items
- * type: array
- * items:
- * $ref: "#/components/schemas/Pipeline_stages"
- * responses:
- * 200:
- * description: The items were successfully imported
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Pipeline_stages"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 405:
- * description: Invalid input data
- * 500:
- * description: Some server error
- *
- */
-router.post('/bulk-import', wrapAsync(async (req, res) => {
- const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
- const link = new URL(referer);
- await Pipeline_stagesService.bulkImport(req, res, true, link.host);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/pipeline_stages/{id}:
- * put:
- * security:
- * - bearerAuth: []
- * tags: [Pipeline_stages]
- * summary: Update the data of the selected item
- * description: Update the data of the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to update
- * required: true
- * schema:
- * type: string
- * requestBody:
- * description: Set new item data
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * id:
- * description: ID of the updated item
- * type: string
- * data:
- * description: Data of the updated item
- * type: object
- * $ref: "#/components/schemas/Pipeline_stages"
- * required:
- * - id
- * responses:
- * 200:
- * description: The item data was successfully updated
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Pipeline_stages"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.put('/:id', wrapAsync(async (req, res) => {
- await Pipeline_stagesService.update(req.body.data, req.body.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/pipeline_stages/{id}:
- * delete:
- * security:
- * - bearerAuth: []
- * tags: [Pipeline_stages]
- * summary: Delete the selected item
- * description: Delete the selected item
- * parameters:
- * - in: path
- * name: id
- * description: Item ID to delete
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: The item was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Pipeline_stages"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.delete('/:id', wrapAsync(async (req, res) => {
- await Pipeline_stagesService.remove(req.params.id, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/pipeline_stages/deleteByIds:
- * post:
- * security:
- * - bearerAuth: []
- * tags: [Pipeline_stages]
- * summary: Delete the selected item list
- * description: Delete the selected item list
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * properties:
- * ids:
- * description: IDs of the updated items
- * type: array
- * responses:
- * 200:
- * description: The items was successfully deleted
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Pipeline_stages"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Items not found
- * 500:
- * description: Some server error
- */
-router.post('/deleteByIds', wrapAsync(async (req, res) => {
- await Pipeline_stagesService.deleteByIds(req.body.data, req.currentUser);
- const payload = true;
- res.status(200).send(payload);
- }));
-
-/**
- * @swagger
- * /api/pipeline_stages:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Pipeline_stages]
- * summary: Get all pipeline_stages
- * description: Get all pipeline_stages
- * responses:
- * 200:
- * description: Pipeline_stages list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Pipeline_stages"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
-*/
-router.get('/', wrapAsync(async (req, res) => {
- const filetype = req.query.filetype
-
- const currentUser = req.currentUser;
- const payload = await Pipeline_stagesDBApi.findAll(
- req.query, { currentUser }
- );
- if (filetype && filetype === 'csv') {
- const fields = ['id','name',
- 'sort_order',
- 'win_probability',
-
- ];
- const opts = { fields };
- try {
- const csv = parse(payload.rows, opts);
- res.status(200).attachment(csv);
- res.send(csv)
-
- } catch (err) {
- console.error(err);
- }
- } else {
- res.status(200).send(payload);
- }
-
-}));
-
-/**
- * @swagger
- * /api/pipeline_stages/count:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Pipeline_stages]
- * summary: Count all pipeline_stages
- * description: Count all pipeline_stages
- * responses:
- * 200:
- * description: Pipeline_stages count successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Pipeline_stages"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/count', wrapAsync(async (req, res) => {
-
- const currentUser = req.currentUser;
- const payload = await Pipeline_stagesDBApi.findAll(
- req.query,
- null,
- { countOnly: true, currentUser }
- );
-
- res.status(200).send(payload);
-}));
-
-/**
- * @swagger
- * /api/pipeline_stages/autocomplete:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Pipeline_stages]
- * summary: Find all pipeline_stages that match search criteria
- * description: Find all pipeline_stages that match search criteria
- * responses:
- * 200:
- * description: Pipeline_stages list successfully received
- * content:
- * application/json:
- * schema:
- * type: array
- * items:
- * $ref: "#/components/schemas/Pipeline_stages"
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Data not found
- * 500:
- * description: Some server error
- */
-router.get('/autocomplete', async (req, res) => {
-
- const payload = await Pipeline_stagesDBApi.findAllAutocomplete(
- req.query.query,
- req.query.limit,
- req.query.offset,
-
- );
-
- res.status(200).send(payload);
-});
-
-/**
- * @swagger
- * /api/pipeline_stages/{id}:
- * get:
- * security:
- * - bearerAuth: []
- * tags: [Pipeline_stages]
- * summary: Get selected item
- * description: Get selected item
- * parameters:
- * - in: path
- * name: id
- * description: ID of item to get
- * required: true
- * schema:
- * type: string
- * responses:
- * 200:
- * description: Selected item successfully received
- * content:
- * application/json:
- * schema:
- * $ref: "#/components/schemas/Pipeline_stages"
- * 400:
- * description: Invalid ID supplied
- * 401:
- * $ref: "#/components/responses/UnauthorizedError"
- * 404:
- * description: Item not found
- * 500:
- * description: Some server error
- */
-router.get('/:id', wrapAsync(async (req, res) => {
- const payload = await Pipeline_stagesDBApi.findBy(
- { id: req.params.id },
- );
-
-
-
- res.status(200).send(payload);
-}));
-
-router.use('/', require('../helpers').commonErrorHandler);
-
-module.exports = router;
diff --git a/backend/src/services/accounts.js b/backend/src/services/accounts.js
deleted file mode 100644
index ca60a54..0000000
--- a/backend/src/services/accounts.js
+++ /dev/null
@@ -1,138 +0,0 @@
-const db = require('../db/models');
-const AccountsDBApi = require('../db/api/accounts');
-const processFile = require("../middlewares/upload");
-const ValidationError = require('./notifications/errors/validation');
-const csv = require('csv-parser');
-const axios = require('axios');
-const config = require('../config');
-const stream = require('stream');
-
-
-
-
-
-module.exports = class AccountsService {
- static async create(data, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- await AccountsDBApi.create(
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async bulkImport(req, res, sendInvitationEmails = true, host) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await processFile(req, res);
- const bufferStream = new stream.PassThrough();
- const results = [];
-
- await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
-
- await new Promise((resolve, reject) => {
- bufferStream
- .pipe(csv())
- .on('data', (data) => results.push(data))
- .on('end', async () => {
- console.log('CSV results', results);
- resolve();
- })
- .on('error', (error) => reject(error));
- })
-
- await AccountsDBApi.bulkImport(results, {
- transaction,
- ignoreDuplicates: true,
- validate: true,
- currentUser: req.currentUser
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async update(data, id, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- let accounts = await AccountsDBApi.findBy(
- {id},
- {transaction},
- );
-
- if (!accounts) {
- throw new ValidationError(
- 'accountsNotFound',
- );
- }
-
- const updatedAccounts = await AccountsDBApi.update(
- id,
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- return updatedAccounts;
-
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async deleteByIds(ids, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await AccountsDBApi.deleteByIds(ids, {
- currentUser,
- transaction,
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async remove(id, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await AccountsDBApi.remove(
- id,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
-
-};
-
-
diff --git a/backend/src/services/activities.js b/backend/src/services/activities.js
deleted file mode 100644
index 8fc3266..0000000
--- a/backend/src/services/activities.js
+++ /dev/null
@@ -1,138 +0,0 @@
-const db = require('../db/models');
-const ActivitiesDBApi = require('../db/api/activities');
-const processFile = require("../middlewares/upload");
-const ValidationError = require('./notifications/errors/validation');
-const csv = require('csv-parser');
-const axios = require('axios');
-const config = require('../config');
-const stream = require('stream');
-
-
-
-
-
-module.exports = class ActivitiesService {
- static async create(data, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- await ActivitiesDBApi.create(
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async bulkImport(req, res, sendInvitationEmails = true, host) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await processFile(req, res);
- const bufferStream = new stream.PassThrough();
- const results = [];
-
- await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
-
- await new Promise((resolve, reject) => {
- bufferStream
- .pipe(csv())
- .on('data', (data) => results.push(data))
- .on('end', async () => {
- console.log('CSV results', results);
- resolve();
- })
- .on('error', (error) => reject(error));
- })
-
- await ActivitiesDBApi.bulkImport(results, {
- transaction,
- ignoreDuplicates: true,
- validate: true,
- currentUser: req.currentUser
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async update(data, id, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- let activities = await ActivitiesDBApi.findBy(
- {id},
- {transaction},
- );
-
- if (!activities) {
- throw new ValidationError(
- 'activitiesNotFound',
- );
- }
-
- const updatedActivities = await ActivitiesDBApi.update(
- id,
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- return updatedActivities;
-
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async deleteByIds(ids, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await ActivitiesDBApi.deleteByIds(ids, {
- currentUser,
- transaction,
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async remove(id, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await ActivitiesDBApi.remove(
- id,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
-
-};
-
-
diff --git a/backend/src/services/contacts.js b/backend/src/services/contacts.js
deleted file mode 100644
index 7189d73..0000000
--- a/backend/src/services/contacts.js
+++ /dev/null
@@ -1,138 +0,0 @@
-const db = require('../db/models');
-const ContactsDBApi = require('../db/api/contacts');
-const processFile = require("../middlewares/upload");
-const ValidationError = require('./notifications/errors/validation');
-const csv = require('csv-parser');
-const axios = require('axios');
-const config = require('../config');
-const stream = require('stream');
-
-
-
-
-
-module.exports = class ContactsService {
- static async create(data, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- await ContactsDBApi.create(
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async bulkImport(req, res, sendInvitationEmails = true, host) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await processFile(req, res);
- const bufferStream = new stream.PassThrough();
- const results = [];
-
- await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
-
- await new Promise((resolve, reject) => {
- bufferStream
- .pipe(csv())
- .on('data', (data) => results.push(data))
- .on('end', async () => {
- console.log('CSV results', results);
- resolve();
- })
- .on('error', (error) => reject(error));
- })
-
- await ContactsDBApi.bulkImport(results, {
- transaction,
- ignoreDuplicates: true,
- validate: true,
- currentUser: req.currentUser
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async update(data, id, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- let contacts = await ContactsDBApi.findBy(
- {id},
- {transaction},
- );
-
- if (!contacts) {
- throw new ValidationError(
- 'contactsNotFound',
- );
- }
-
- const updatedContacts = await ContactsDBApi.update(
- id,
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- return updatedContacts;
-
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async deleteByIds(ids, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await ContactsDBApi.deleteByIds(ids, {
- currentUser,
- transaction,
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async remove(id, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await ContactsDBApi.remove(
- id,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
-
-};
-
-
diff --git a/backend/src/services/deals.js b/backend/src/services/deals.js
deleted file mode 100644
index a611dab..0000000
--- a/backend/src/services/deals.js
+++ /dev/null
@@ -1,138 +0,0 @@
-const db = require('../db/models');
-const DealsDBApi = require('../db/api/deals');
-const processFile = require("../middlewares/upload");
-const ValidationError = require('./notifications/errors/validation');
-const csv = require('csv-parser');
-const axios = require('axios');
-const config = require('../config');
-const stream = require('stream');
-
-
-
-
-
-module.exports = class DealsService {
- static async create(data, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- await DealsDBApi.create(
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async bulkImport(req, res, sendInvitationEmails = true, host) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await processFile(req, res);
- const bufferStream = new stream.PassThrough();
- const results = [];
-
- await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
-
- await new Promise((resolve, reject) => {
- bufferStream
- .pipe(csv())
- .on('data', (data) => results.push(data))
- .on('end', async () => {
- console.log('CSV results', results);
- resolve();
- })
- .on('error', (error) => reject(error));
- })
-
- await DealsDBApi.bulkImport(results, {
- transaction,
- ignoreDuplicates: true,
- validate: true,
- currentUser: req.currentUser
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async update(data, id, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- let deals = await DealsDBApi.findBy(
- {id},
- {transaction},
- );
-
- if (!deals) {
- throw new ValidationError(
- 'dealsNotFound',
- );
- }
-
- const updatedDeals = await DealsDBApi.update(
- id,
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- return updatedDeals;
-
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async deleteByIds(ids, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await DealsDBApi.deleteByIds(ids, {
- currentUser,
- transaction,
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async remove(id, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await DealsDBApi.remove(
- id,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
-
-};
-
-
diff --git a/backend/src/services/lead_sources.js b/backend/src/services/lead_sources.js
deleted file mode 100644
index a216daf..0000000
--- a/backend/src/services/lead_sources.js
+++ /dev/null
@@ -1,138 +0,0 @@
-const db = require('../db/models');
-const Lead_sourcesDBApi = require('../db/api/lead_sources');
-const processFile = require("../middlewares/upload");
-const ValidationError = require('./notifications/errors/validation');
-const csv = require('csv-parser');
-const axios = require('axios');
-const config = require('../config');
-const stream = require('stream');
-
-
-
-
-
-module.exports = class Lead_sourcesService {
- static async create(data, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- await Lead_sourcesDBApi.create(
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async bulkImport(req, res, sendInvitationEmails = true, host) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await processFile(req, res);
- const bufferStream = new stream.PassThrough();
- const results = [];
-
- await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
-
- await new Promise((resolve, reject) => {
- bufferStream
- .pipe(csv())
- .on('data', (data) => results.push(data))
- .on('end', async () => {
- console.log('CSV results', results);
- resolve();
- })
- .on('error', (error) => reject(error));
- })
-
- await Lead_sourcesDBApi.bulkImport(results, {
- transaction,
- ignoreDuplicates: true,
- validate: true,
- currentUser: req.currentUser
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async update(data, id, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- let lead_sources = await Lead_sourcesDBApi.findBy(
- {id},
- {transaction},
- );
-
- if (!lead_sources) {
- throw new ValidationError(
- 'lead_sourcesNotFound',
- );
- }
-
- const updatedLead_sources = await Lead_sourcesDBApi.update(
- id,
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- return updatedLead_sources;
-
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async deleteByIds(ids, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await Lead_sourcesDBApi.deleteByIds(ids, {
- currentUser,
- transaction,
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async remove(id, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await Lead_sourcesDBApi.remove(
- id,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
-
-};
-
-
diff --git a/backend/src/services/leads.js b/backend/src/services/leads.js
deleted file mode 100644
index 4aff6d5..0000000
--- a/backend/src/services/leads.js
+++ /dev/null
@@ -1,138 +0,0 @@
-const db = require('../db/models');
-const LeadsDBApi = require('../db/api/leads');
-const processFile = require("../middlewares/upload");
-const ValidationError = require('./notifications/errors/validation');
-const csv = require('csv-parser');
-const axios = require('axios');
-const config = require('../config');
-const stream = require('stream');
-
-
-
-
-
-module.exports = class LeadsService {
- static async create(data, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- await LeadsDBApi.create(
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async bulkImport(req, res, sendInvitationEmails = true, host) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await processFile(req, res);
- const bufferStream = new stream.PassThrough();
- const results = [];
-
- await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
-
- await new Promise((resolve, reject) => {
- bufferStream
- .pipe(csv())
- .on('data', (data) => results.push(data))
- .on('end', async () => {
- console.log('CSV results', results);
- resolve();
- })
- .on('error', (error) => reject(error));
- })
-
- await LeadsDBApi.bulkImport(results, {
- transaction,
- ignoreDuplicates: true,
- validate: true,
- currentUser: req.currentUser
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async update(data, id, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- let leads = await LeadsDBApi.findBy(
- {id},
- {transaction},
- );
-
- if (!leads) {
- throw new ValidationError(
- 'leadsNotFound',
- );
- }
-
- const updatedLeads = await LeadsDBApi.update(
- id,
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- return updatedLeads;
-
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async deleteByIds(ids, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await LeadsDBApi.deleteByIds(ids, {
- currentUser,
- transaction,
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async remove(id, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await LeadsDBApi.remove(
- id,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
-
-};
-
-
diff --git a/backend/src/services/notifications/list.js b/backend/src/services/notifications/list.js
index 17242b0..5c50707 100644
--- a/backend/src/services/notifications/list.js
+++ b/backend/src/services/notifications/list.js
@@ -1,6 +1,6 @@
const errors = {
app: {
- title: 'Sales Pipeline CRM',
+ title: 'Coaching SaaS Workspace',
},
auth: {
diff --git a/backend/src/services/pipeline_stages.js b/backend/src/services/pipeline_stages.js
deleted file mode 100644
index 762b458..0000000
--- a/backend/src/services/pipeline_stages.js
+++ /dev/null
@@ -1,138 +0,0 @@
-const db = require('../db/models');
-const Pipeline_stagesDBApi = require('../db/api/pipeline_stages');
-const processFile = require("../middlewares/upload");
-const ValidationError = require('./notifications/errors/validation');
-const csv = require('csv-parser');
-const axios = require('axios');
-const config = require('../config');
-const stream = require('stream');
-
-
-
-
-
-module.exports = class Pipeline_stagesService {
- static async create(data, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- await Pipeline_stagesDBApi.create(
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async bulkImport(req, res, sendInvitationEmails = true, host) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await processFile(req, res);
- const bufferStream = new stream.PassThrough();
- const results = [];
-
- await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
-
- await new Promise((resolve, reject) => {
- bufferStream
- .pipe(csv())
- .on('data', (data) => results.push(data))
- .on('end', async () => {
- console.log('CSV results', results);
- resolve();
- })
- .on('error', (error) => reject(error));
- })
-
- await Pipeline_stagesDBApi.bulkImport(results, {
- transaction,
- ignoreDuplicates: true,
- validate: true,
- currentUser: req.currentUser
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async update(data, id, currentUser) {
- const transaction = await db.sequelize.transaction();
- try {
- let pipeline_stages = await Pipeline_stagesDBApi.findBy(
- {id},
- {transaction},
- );
-
- if (!pipeline_stages) {
- throw new ValidationError(
- 'pipeline_stagesNotFound',
- );
- }
-
- const updatedPipeline_stages = await Pipeline_stagesDBApi.update(
- id,
- data,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- return updatedPipeline_stages;
-
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- };
-
- static async deleteByIds(ids, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await Pipeline_stagesDBApi.deleteByIds(ids, {
- currentUser,
- transaction,
- });
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
- static async remove(id, currentUser) {
- const transaction = await db.sequelize.transaction();
-
- try {
- await Pipeline_stagesDBApi.remove(
- id,
- {
- currentUser,
- transaction,
- },
- );
-
- await transaction.commit();
- } catch (error) {
- await transaction.rollback();
- throw error;
- }
- }
-
-
-};
-
-
diff --git a/backend/src/services/search.js b/backend/src/services/search.js
index 190a1fc..dafa5aa 100644
--- a/backend/src/services/search.js
+++ b/backend/src/services/search.js
@@ -1,15 +1,9 @@
const db = require('../db/models');
const ValidationError = require('./notifications/errors/validation');
-const Sequelize = db.Sequelize;
-const Op = Sequelize.Op;
+const Op = db.Sequelize.Op;
-/**
- * @param {string} permission
- * @param {object} currentUser
- */
async function checkPermissions(permission, currentUser) {
-
if (!currentUser) {
throw new ValidationError('auth.unauthorized');
}
@@ -22,288 +16,93 @@ async function checkPermissions(permission, currentUser) {
return true;
}
- try {
- if (!currentUser.app_role) {
- throw new ValidationError('auth.forbidden');
- }
-
- const permissions = await currentUser.app_role.getPermissions();
-
- return !!permissions.find((p) => p.name === permission);
- } catch (e) {
- throw e;
+ if (!currentUser.app_role) {
+ throw new ValidationError('auth.forbidden');
}
+
+ const permissions = await currentUser.app_role.getPermissions();
+ return !!permissions.find((p) => p.name === permission);
+}
+
+function textMatch(fields, searchQuery) {
+ return {
+ [Op.or]: fields.map((field) => ({
+ [field]: { [Op.iLike]: `%${searchQuery}%` },
+ })),
+ };
+}
+
+function searchResult(type, label, description, path) {
+ return {
+ type,
+ label,
+ description,
+ path,
+ };
}
module.exports = class SearchService {
- static async search(searchQuery, currentUser ) {
- try {
- if (!searchQuery) {
- throw new ValidationError('iam.errors.searchQueryRequired');
- }
- const tableColumns = {
-
-
-
-
-
- "users": [
-
- "firstName",
-
- "lastName",
-
- "phoneNumber",
-
- "email",
-
- ],
-
-
-
-
-
-
-
-
- "accounts": [
-
- "name",
-
- "domain",
-
- "industry",
-
- "phone",
-
- "website",
-
- "address",
-
- "notes",
-
- ],
-
-
-
-
-
-
- "contacts": [
-
- "full_name",
-
- "email",
-
- "phone",
-
- "job_title",
-
- "linkedin_url",
-
- "notes",
-
- ],
-
-
-
-
-
-
- "lead_sources": [
-
- "name",
-
- "description",
-
- ],
-
-
-
-
-
-
- "leads": [
-
- "lead_name",
-
- "company_name",
-
- "email",
-
- "phone",
-
- "notes",
-
- ],
-
-
-
-
-
-
- "pipeline_stages": [
-
- "name",
-
- ],
-
-
-
-
-
-
- "deals": [
-
- "name",
-
- "currency",
-
- "loss_reason",
-
- "description",
-
- ],
-
-
-
-
-
-
- "activities": [
-
- "subject",
-
- "details",
-
- ],
-
-
- };
- const columnsInt = {
-
-
-
-
-
-
-
-
-
-
- "accounts": [
-
- "employee_count",
-
- "annual_revenue",
-
- ],
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "pipeline_stages": [
-
- "sort_order",
-
- "win_probability",
-
- ],
-
-
-
-
-
- "deals": [
-
- "amount",
-
- ],
-
-
-
-
-
-
- };
-
- let allFoundRecords = [];
-
- for (const tableName in tableColumns) {
- if (tableColumns.hasOwnProperty(tableName)) {
- const attributesToSearch = tableColumns[tableName];
- const attributesIntToSearch = columnsInt[tableName] || [];
- const whereCondition = {
- [Op.or]: [
- ...attributesToSearch.map(attribute => ({
- [attribute]: {
- [Op.iLike] : `%${searchQuery}%`,
- },
- })),
- ...attributesIntToSearch.map(attribute => (
- Sequelize.where(
- Sequelize.cast(Sequelize.col(`${tableName}.${attribute}`), 'varchar'),
- { [Op.iLike]: `%${searchQuery}%` }
- )
- )),
- ],
- };
-
-
-
- const hasPermission = await checkPermissions(`READ_${tableName.toUpperCase()}`, currentUser);
- if (!hasPermission) {
- continue;
- }
-
- const foundRecords = await db[tableName].findAll({
- where: whereCondition,
- attributes: [...tableColumns[tableName], 'id', ...attributesIntToSearch],
- });
-
- const modifiedRecords = foundRecords.map((record) => {
- const matchAttribute = [];
-
- for (const attribute of attributesToSearch) {
- if (record[attribute]?.toLowerCase()?.includes(searchQuery.toLowerCase())) {
- matchAttribute.push(attribute);
- }
- }
-
- for (const attribute of attributesIntToSearch) {
- const castedValue = String(record[attribute]);
- if (castedValue && castedValue.toLowerCase().includes(searchQuery.toLowerCase())) {
- matchAttribute.push(attribute);
- }
- }
-
- return {
- ...record.get(),
- matchAttribute,
- tableName,
- };
- });
-
- allFoundRecords = allFoundRecords.concat(modifiedRecords);
- }
- }
-
- return allFoundRecords;
- } catch (error) {
- throw error;
+ static async search(searchQuery, currentUser) {
+ if (!searchQuery) {
+ throw new ValidationError('iam.errors.searchQueryRequired');
}
+
+ await checkPermissions('search', currentUser);
+
+ const [clients, sessions, actionItems, resources, packages] = await Promise.all([
+ db.clients.findAll({
+ where: textMatch(['name', 'email', 'company', 'role_title', 'goals', 'notes'], searchQuery),
+ limit: 10,
+ }),
+ db.sessions.findAll({
+ where: textMatch(['title', 'ai_summary', 'key_topics', 'commitments', 'homework'], searchQuery),
+ limit: 10,
+ }),
+ db.action_items.findAll({
+ where: textMatch(['title', 'notes'], searchQuery),
+ limit: 10,
+ }),
+ db.resources.findAll({
+ where: textMatch(['title', 'description', 'url'], searchQuery),
+ limit: 10,
+ }),
+ db.packages.findAll({
+ where: textMatch(['title', 'description', 'price', 'duration'], searchQuery),
+ limit: 10,
+ }),
+ ]);
+
+ return [
+ ...clients.map((client) => searchResult(
+ 'Client',
+ client.name,
+ client.email || client.company,
+ '/clients',
+ )),
+ ...sessions.map((session) => searchResult(
+ 'Session',
+ session.title,
+ session.ai_summary,
+ '/session-memory',
+ )),
+ ...actionItems.map((actionItem) => searchResult(
+ 'Action Item',
+ actionItem.title,
+ actionItem.notes,
+ '/dashboard',
+ )),
+ ...resources.map((resource) => searchResult(
+ 'Resource',
+ resource.title,
+ resource.description,
+ '/client-portal',
+ )),
+ ...packages.map((coachingPackage) => searchResult(
+ 'Package',
+ coachingPackage.title,
+ coachingPackage.description,
+ '/',
+ )),
+ ];
}
-}
\ No newline at end of file
+};
diff --git a/frontend/README.md b/frontend/README.md
index 9b0b60d..9b25f67 100644
--- a/frontend/README.md
+++ b/frontend/README.md
@@ -1,4 +1,4 @@
-# Sales Pipeline CRM
+# Coaching SaaS Workspace
## This project was generated by Flatlogic Platform.
## Install
@@ -89,4 +89,3 @@ The **docker folder** contains a couple of helper scripts:
9. Stop services:
9.1. Just press `Ctr+C`
-
diff --git a/frontend/src/components/Accounts/CardAccounts.tsx b/frontend/src/components/Accounts/CardAccounts.tsx
deleted file mode 100644
index 8be2c27..0000000
--- a/frontend/src/components/Accounts/CardAccounts.tsx
+++ /dev/null
@@ -1,255 +0,0 @@
-import React from 'react';
-import ImageField from '../ImageField';
-import ListActionsPopover from '../ListActionsPopover';
-import { useAppSelector } from '../../stores/hooks';
-import dataFormatter from '../../helpers/dataFormatter';
-import { Pagination } from '../Pagination';
-import {saveFile} from "../../helpers/fileSaver";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- accounts: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const CardAccounts = ({
- accounts,
- loading,
- onDelete,
- currentPage,
- numPages,
- onPageChange,
-}: Props) => {
- const asideScrollbarsStyle = useAppSelector(
- (state) => state.style.asideScrollbarsStyle,
- );
- const bgColor = useAppSelector((state) => state.style.cardsColor);
- const darkMode = useAppSelector((state) => state.style.darkMode);
- const corners = useAppSelector((state) => state.style.corners);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ACCOUNTS')
-
-
- return (
-
- {loading &&
}
-
- {!loading && accounts.map((item, index) => (
- -
-
-
-
-
- {item.name}
-
-
-
-
-
-
-
-
-
-
-
-
- AccountName
-
-
-
- { item.name }
-
-
-
-
-
-
-
-
-
- Domain
-
-
-
- { item.domain }
-
-
-
-
-
-
-
-
-
- Industry
-
-
-
- { item.industry }
-
-
-
-
-
-
-
-
-
- EmployeeCount
-
-
-
- { item.employee_count }
-
-
-
-
-
-
-
-
-
- AnnualRevenue
-
-
-
- { item.annual_revenue }
-
-
-
-
-
-
-
-
-
- Phone
-
-
-
- { item.phone }
-
-
-
-
-
-
-
-
-
- Website
-
-
-
- { item.website }
-
-
-
-
-
-
-
-
-
- Address
-
-
-
- { item.address }
-
-
-
-
-
-
-
-
-
- Owner
-
-
-
- { dataFormatter.usersOneListFormatter(item.owner) }
-
-
-
-
-
-
-
-
-
- AccountStatus
-
-
-
- { item.account_status }
-
-
-
-
-
-
-
-
-
- LastContactedAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_contacted_at) }
-
-
-
-
-
-
-
-
-
- NextFollow-upAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
-
-
-
-
-
-
-
-
-
- Notes
-
-
-
- { item.notes }
-
-
-
-
-
-
-
-
- ))}
- {!loading && accounts.length === 0 && (
-
- )}
-
-
-
- );
-};
-
-export default CardAccounts;
diff --git a/frontend/src/components/Accounts/ListAccounts.tsx b/frontend/src/components/Accounts/ListAccounts.tsx
deleted file mode 100644
index be7fb8e..0000000
--- a/frontend/src/components/Accounts/ListAccounts.tsx
+++ /dev/null
@@ -1,184 +0,0 @@
-import React from 'react';
-import CardBox from '../CardBox';
-import ImageField from '../ImageField';
-import dataFormatter from '../../helpers/dataFormatter';
-import {saveFile} from "../../helpers/fileSaver";
-import ListActionsPopover from "../ListActionsPopover";
-import {useAppSelector} from "../../stores/hooks";
-import {Pagination} from "../Pagination";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- accounts: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const ListAccounts = ({ accounts, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ACCOUNTS')
-
- const corners = useAppSelector((state) => state.style.corners);
- const bgColor = useAppSelector((state) => state.style.cardsColor);
-
-
- return (
- <>
-
- {loading &&
}
- {!loading && accounts.map((item) => (
-
-
-
-
-
dark:divide-dark-700 overflow-x-auto'
- }
- >
-
-
-
-
AccountName
-
{ item.name }
-
-
-
-
-
-
-
Domain
-
{ item.domain }
-
-
-
-
-
-
-
Industry
-
{ item.industry }
-
-
-
-
-
-
-
EmployeeCount
-
{ item.employee_count }
-
-
-
-
-
-
-
AnnualRevenue
-
{ item.annual_revenue }
-
-
-
-
-
-
-
Phone
-
{ item.phone }
-
-
-
-
-
-
-
Website
-
{ item.website }
-
-
-
-
-
-
-
Address
-
{ item.address }
-
-
-
-
-
-
-
Owner
-
{ dataFormatter.usersOneListFormatter(item.owner) }
-
-
-
-
-
-
-
AccountStatus
-
{ item.account_status }
-
-
-
-
-
-
-
LastContactedAt
-
{ dataFormatter.dateTimeFormatter(item.last_contacted_at) }
-
-
-
-
-
-
-
NextFollow-upAt
-
{ dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
-
-
-
-
-
-
-
Notes
-
{ item.notes }
-
-
-
-
-
-
-
-
-
- ))}
- {!loading && accounts.length === 0 && (
-
- )}
-
-
- >
- )
-};
-
-export default ListAccounts
\ No newline at end of file
diff --git a/frontend/src/components/Accounts/TableAccounts.tsx b/frontend/src/components/Accounts/TableAccounts.tsx
deleted file mode 100644
index 9a34da6..0000000
--- a/frontend/src/components/Accounts/TableAccounts.tsx
+++ /dev/null
@@ -1,476 +0,0 @@
-import React, { useEffect, useState, useMemo } from 'react'
-import { createPortal } from 'react-dom';
-import { ToastContainer, toast } from 'react-toastify';
-import BaseButton from '../BaseButton'
-import CardBoxModal from '../CardBoxModal'
-import CardBox from "../CardBox";
-import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/accounts/accountsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import { Field, Form, Formik } from "formik";
-import {
- DataGrid,
- GridColDef,
-} from '@mui/x-data-grid';
-import {loadColumns} from "./configureAccountsCols";
-import _ from 'lodash';
-import dataFormatter from '../../helpers/dataFormatter'
-import {dataGridStyles} from "../../styles";
-
-
-import CardAccounts from './CardAccounts';
-
-
-const perPage = 10
-
-const TableSampleAccounts = ({ filterItems, setFilterItems, filters, showGrid }) => {
- const notify = (type, msg) => toast( msg, {type, position: "bottom-center"});
-
- const dispatch = useAppDispatch();
- const router = useRouter();
-
- const pagesList = [];
- const [id, setId] = useState(null);
- const [currentPage, setCurrentPage] = useState(0);
- const [filterRequest, setFilterRequest] = React.useState('');
- const [columns, setColumns] = useState([]);
- const [selectedRows, setSelectedRows] = useState([]);
- const [sortModel, setSortModel] = useState([
- {
- field: '',
- sort: 'desc',
- },
- ]);
-
- const { accounts, loading, count, notify: accountsNotify, refetch } = useAppSelector((state) => state.accounts)
- const { currentUser } = useAppSelector((state) => state.auth);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
- const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
- const corners = useAppSelector((state) => state.style.corners);
- const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
- for (let i = 0; i < numPages; i++) {
- pagesList.push(i);
- }
-
- const loadData = async (page = currentPage, request = filterRequest) => {
- if (page !== currentPage) setCurrentPage(page);
- if (request !== filterRequest) setFilterRequest(request);
- const { sort, field } = sortModel[0];
-
- const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`;
- dispatch(fetch({ limit: perPage, page, query }));
- };
-
- useEffect(() => {
- if (accountsNotify.showNotification) {
- notify(accountsNotify.typeNotification, accountsNotify.textNotification);
- }
- }, [accountsNotify.showNotification]);
-
- useEffect(() => {
- if (!currentUser) return;
- loadData();
- }, [sortModel, currentUser]);
-
- useEffect(() => {
- if (refetch) {
- loadData(0);
- dispatch(setRefetch(false));
- }
- }, [refetch, dispatch]);
-
- const [isModalInfoActive, setIsModalInfoActive] = useState(false)
- const [isModalTrashActive, setIsModalTrashActive] = useState(false)
-
- const handleModalAction = () => {
- setIsModalInfoActive(false)
- setIsModalTrashActive(false)
- }
-
-
-
-
-
- const handleDeleteModalAction = (id: string) => {
- setId(id)
- setIsModalTrashActive(true)
- }
- const handleDeleteAction = async () => {
- if (id) {
- await dispatch(deleteItem(id));
- await loadData(0);
- setIsModalTrashActive(false);
- }
- };
-
- const generateFilterRequests = useMemo(() => {
- let request = '&';
- filterItems.forEach((item) => {
- const isRangeFilter = filters.find(
- (filter) =>
- filter.title === item.fields.selectedField &&
- (filter.number || filter.date),
- );
-
- if (isRangeFilter) {
- const from = item.fields.filterValueFrom;
- const to = item.fields.filterValueTo;
- if (from) {
- request += `${item.fields.selectedField}Range=${from}&`;
- }
- if (to) {
- request += `${item.fields.selectedField}Range=${to}&`;
- }
- } else {
- const value = item.fields.filterValue;
- if (value) {
- request += `${item.fields.selectedField}=${value}&`;
- }
- }
- });
- return request;
- }, [filterItems, filters]);
-
- const deleteFilter = (value) => {
- const newItems = filterItems.filter((item) => item.id !== value);
-
- if (newItems.length) {
- setFilterItems(newItems);
- } else {
- loadData(0, '');
-
- setFilterItems(newItems);
- }
- };
-
- const handleSubmit = () => {
- loadData(0, generateFilterRequests);
-
- };
-
- const handleChange = (id) => (e) => {
- const value = e.target.value;
- const name = e.target.name;
-
- setFilterItems(
- filterItems.map((item) => {
- if (item.id !== id) return item;
- if (name === 'selectedField') return { id, fields: { [name]: value } };
-
- return { id, fields: { ...item.fields, [name]: value } }
- }),
- );
- };
-
- const handleReset = () => {
- setFilterItems([]);
- loadData(0, '');
-
- };
-
- const onPageChange = (page: number) => {
- loadData(page);
- setCurrentPage(page);
- };
-
-
- useEffect(() => {
- if (!currentUser) return;
-
- loadColumns(
- handleDeleteModalAction,
- `accounts`,
- currentUser,
- ).then((newCols) => setColumns(newCols));
- }, [currentUser]);
-
-
-
- const handleTableSubmit = async (id: string, data) => {
-
- if (!_.isEmpty(data)) {
- await dispatch(update({ id, data }))
- .unwrap()
- .then((res) => res)
- .catch((err) => {
- throw new Error(err);
- });
- }
- };
-
- const onDeleteRows = async (selectedRows) => {
- await dispatch(deleteItemsByIds(selectedRows));
- await loadData(0);
- };
-
- const controlClasses =
- 'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' +
- ` ${bgColor} ${focusRing} ${corners} ` +
- 'dark:bg-slate-800 border';
-
-
- const dataGrid = (
-
- `datagrid--row`}
- rows={accounts ?? []}
- columns={columns}
- initialState={{
- pagination: {
- paginationModel: {
- pageSize: 10,
- },
- },
- }}
- disableRowSelectionOnClick
- onProcessRowUpdateError={(params) => {
- console.log('Error', params);
- }}
- processRowUpdate={async (newRow, oldRow) => {
- const data = dataFormatter.dataGridEditFormatter(newRow);
-
- try {
- await handleTableSubmit(newRow.id, data);
- return newRow;
- } catch {
- return oldRow;
- }
- }}
- sortingMode={'server'}
- checkboxSelection
- onRowSelectionModelChange={(ids) => {
- setSelectedRows(ids)
- }}
- onSortModelChange={(params) => {
- params.length
- ? setSortModel(params)
- : setSortModel([{ field: '', sort: 'desc' }]);
- }}
- rowCount={count}
- pageSizeOptions={[10]}
- paginationMode={'server'}
- loading={loading}
- onPaginationModelChange={(params) => {
- onPageChange(params.page);
- }}
- />
-
- )
-
- return (
- <>
- {filterItems && Array.isArray( filterItems ) && filterItems.length ?
-
- null}
- >
-
-
- : null
- }
-
- Are you sure you want to delete this item?
-
-
-
- {accounts && Array.isArray(accounts) && !showGrid && (
-
- )}
-
-
-
- {showGrid && dataGrid}
-
-
- {selectedRows.length > 0 &&
- createPortal(
- onDeleteRows(selectedRows)}
- />,
- document.getElementById('delete-rows-button'),
- )}
-
- >
- )
-}
-
-export default TableSampleAccounts
diff --git a/frontend/src/components/Accounts/configureAccountsCols.tsx b/frontend/src/components/Accounts/configureAccountsCols.tsx
deleted file mode 100644
index e1413a4..0000000
--- a/frontend/src/components/Accounts/configureAccountsCols.tsx
+++ /dev/null
@@ -1,278 +0,0 @@
-import React from 'react';
-import BaseIcon from '../BaseIcon';
-import { mdiEye, mdiTrashCan, mdiPencilOutline } from '@mdi/js';
-import axios from 'axios';
-import {
- GridActionsCellItem,
- GridRowParams,
- GridValueGetterParams,
-} from '@mui/x-data-grid';
-import ImageField from '../ImageField';
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter'
-import DataGridMultiSelect from "../DataGridMultiSelect";
-import ListActionsPopover from '../ListActionsPopover';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-type Params = (id: string) => void;
-
-export const loadColumns = async (
- onDelete: Params,
- entityName: string,
-
- user
-
-) => {
- async function callOptionsApi(entityName: string) {
-
- if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
-
- try {
- const data = await axios(`/${entityName}/autocomplete?limit=100`);
- return data.data;
- } catch (error) {
- console.log(error);
- return [];
- }
- }
-
- const hasUpdatePermission = hasPermission(user, 'UPDATE_ACCOUNTS')
-
- return [
-
- {
- field: 'name',
- headerName: 'AccountName',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'domain',
- headerName: 'Domain',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'industry',
- headerName: 'Industry',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'employee_count',
- headerName: 'EmployeeCount',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'number',
-
- },
-
- {
- field: 'annual_revenue',
- headerName: 'AnnualRevenue',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'number',
-
- },
-
- {
- field: 'phone',
- headerName: 'Phone',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'website',
- headerName: 'Website',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'address',
- headerName: 'Address',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'owner',
- headerName: 'Owner',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('users'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'account_status',
- headerName: 'AccountStatus',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'last_contacted_at',
- headerName: 'LastContactedAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.last_contacted_at),
-
- },
-
- {
- field: 'next_follow_up_at',
- headerName: 'NextFollow-upAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.next_follow_up_at),
-
- },
-
- {
- field: 'notes',
- headerName: 'Notes',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'actions',
- type: 'actions',
- minWidth: 30,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
- getActions: (params: GridRowParams) => {
-
- return [
-
-
-
,
- ]
- },
- },
- ];
-};
diff --git a/frontend/src/components/Activities/CardActivities.tsx b/frontend/src/components/Activities/CardActivities.tsx
deleted file mode 100644
index 695624b..0000000
--- a/frontend/src/components/Activities/CardActivities.tsx
+++ /dev/null
@@ -1,274 +0,0 @@
-import React from 'react';
-import ImageField from '../ImageField';
-import ListActionsPopover from '../ListActionsPopover';
-import { useAppSelector } from '../../stores/hooks';
-import dataFormatter from '../../helpers/dataFormatter';
-import { Pagination } from '../Pagination';
-import {saveFile} from "../../helpers/fileSaver";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- activities: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const CardActivities = ({
- activities,
- loading,
- onDelete,
- currentPage,
- numPages,
- onPageChange,
-}: Props) => {
- const asideScrollbarsStyle = useAppSelector(
- (state) => state.style.asideScrollbarsStyle,
- );
- const bgColor = useAppSelector((state) => state.style.cardsColor);
- const darkMode = useAppSelector((state) => state.style.darkMode);
- const corners = useAppSelector((state) => state.style.corners);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ACTIVITIES')
-
-
- return (
-
- {loading &&
}
-
- {!loading && activities.map((item, index) => (
- -
-
-
-
-
- {item.subject}
-
-
-
-
-
-
-
-
-
-
-
-
- ActivityType
-
-
-
- { item.activity_type }
-
-
-
-
-
-
-
-
-
- Subject
-
-
-
- { item.subject }
-
-
-
-
-
-
-
-
-
- Details
-
-
-
- { item.details }
-
-
-
-
-
-
-
-
-
- Owner
-
-
-
- { dataFormatter.usersOneListFormatter(item.owner) }
-
-
-
-
-
-
-
-
-
- Lead
-
-
-
- { dataFormatter.leadsOneListFormatter(item.lead) }
-
-
-
-
-
-
-
-
-
- Deal
-
-
-
- { dataFormatter.dealsOneListFormatter(item.deal) }
-
-
-
-
-
-
-
-
-
- Contact
-
-
-
- { dataFormatter.contactsOneListFormatter(item.contact) }
-
-
-
-
-
-
-
-
-
- Account
-
-
-
- { dataFormatter.accountsOneListFormatter(item.account) }
-
-
-
-
-
-
-
-
-
- ActivityAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.activity_at) }
-
-
-
-
-
-
-
-
-
- DueAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.due_at) }
-
-
-
-
-
-
-
-
-
- CompletedAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.completed_at) }
-
-
-
-
-
-
-
-
-
- Status
-
-
-
- { item.status }
-
-
-
-
-
-
-
-
-
- Priority
-
-
-
- { item.priority }
-
-
-
-
-
-
-
-
-
- Attachments
-
-
-
- {dataFormatter.filesFormatter(item.attachments).map(link => (
-
- ))}
-
-
-
-
-
-
-
-
- ))}
- {!loading && activities.length === 0 && (
-
- )}
-
-
-
- );
-};
-
-export default CardActivities;
diff --git a/frontend/src/components/Activities/ListActivities.tsx b/frontend/src/components/Activities/ListActivities.tsx
deleted file mode 100644
index 829e62f..0000000
--- a/frontend/src/components/Activities/ListActivities.tsx
+++ /dev/null
@@ -1,199 +0,0 @@
-import React from 'react';
-import CardBox from '../CardBox';
-import ImageField from '../ImageField';
-import dataFormatter from '../../helpers/dataFormatter';
-import {saveFile} from "../../helpers/fileSaver";
-import ListActionsPopover from "../ListActionsPopover";
-import {useAppSelector} from "../../stores/hooks";
-import {Pagination} from "../Pagination";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- activities: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const ListActivities = ({ activities, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ACTIVITIES')
-
- const corners = useAppSelector((state) => state.style.corners);
- const bgColor = useAppSelector((state) => state.style.cardsColor);
-
-
- return (
- <>
-
- {loading &&
}
- {!loading && activities.map((item) => (
-
-
-
-
-
dark:divide-dark-700 overflow-x-auto'
- }
- >
-
-
-
-
ActivityType
-
{ item.activity_type }
-
-
-
-
-
-
-
Subject
-
{ item.subject }
-
-
-
-
-
-
-
Details
-
{ item.details }
-
-
-
-
-
-
-
Owner
-
{ dataFormatter.usersOneListFormatter(item.owner) }
-
-
-
-
-
-
-
Lead
-
{ dataFormatter.leadsOneListFormatter(item.lead) }
-
-
-
-
-
-
-
Deal
-
{ dataFormatter.dealsOneListFormatter(item.deal) }
-
-
-
-
-
-
-
Contact
-
{ dataFormatter.contactsOneListFormatter(item.contact) }
-
-
-
-
-
-
-
Account
-
{ dataFormatter.accountsOneListFormatter(item.account) }
-
-
-
-
-
-
-
ActivityAt
-
{ dataFormatter.dateTimeFormatter(item.activity_at) }
-
-
-
-
-
-
-
DueAt
-
{ dataFormatter.dateTimeFormatter(item.due_at) }
-
-
-
-
-
-
-
CompletedAt
-
{ dataFormatter.dateTimeFormatter(item.completed_at) }
-
-
-
-
-
-
-
Status
-
{ item.status }
-
-
-
-
-
-
-
Priority
-
{ item.priority }
-
-
-
-
-
-
-
Attachments
- {dataFormatter.filesFormatter(item.attachments).map(link => (
-
- ))}
-
-
-
-
-
-
-
-
-
- ))}
- {!loading && activities.length === 0 && (
-
- )}
-
-
- >
- )
-};
-
-export default ListActivities
\ No newline at end of file
diff --git a/frontend/src/components/Activities/TableActivities.tsx b/frontend/src/components/Activities/TableActivities.tsx
deleted file mode 100644
index d08d62d..0000000
--- a/frontend/src/components/Activities/TableActivities.tsx
+++ /dev/null
@@ -1,489 +0,0 @@
-import React, { useEffect, useState, useMemo } from 'react'
-import { createPortal } from 'react-dom';
-import { ToastContainer, toast } from 'react-toastify';
-import BaseButton from '../BaseButton'
-import CardBoxModal from '../CardBoxModal'
-import CardBox from "../CardBox";
-import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/activities/activitiesSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import { Field, Form, Formik } from "formik";
-import {
- DataGrid,
- GridColDef,
-} from '@mui/x-data-grid';
-import {loadColumns} from "./configureActivitiesCols";
-import _ from 'lodash';
-import dataFormatter from '../../helpers/dataFormatter'
-import {dataGridStyles} from "../../styles";
-
-
-import BigCalendar from "../BigCalendar";
-import { SlotInfo } from 'react-big-calendar';
-
-
-const perPage = 100
-
-const TableSampleActivities = ({ filterItems, setFilterItems, filters, showGrid }) => {
- const notify = (type, msg) => toast( msg, {type, position: "bottom-center"});
-
- const dispatch = useAppDispatch();
- const router = useRouter();
-
- const pagesList = [];
- const [id, setId] = useState(null);
- const [currentPage, setCurrentPage] = useState(0);
- const [filterRequest, setFilterRequest] = React.useState('');
- const [columns, setColumns] = useState([]);
- const [selectedRows, setSelectedRows] = useState([]);
- const [sortModel, setSortModel] = useState([
- {
- field: '',
- sort: 'desc',
- },
- ]);
-
- const { activities, loading, count, notify: activitiesNotify, refetch } = useAppSelector((state) => state.activities)
- const { currentUser } = useAppSelector((state) => state.auth);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
- const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
- const corners = useAppSelector((state) => state.style.corners);
- const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
- for (let i = 0; i < numPages; i++) {
- pagesList.push(i);
- }
-
- const loadData = async (page = currentPage, request = filterRequest) => {
- if (page !== currentPage) setCurrentPage(page);
- if (request !== filterRequest) setFilterRequest(request);
- const { sort, field } = sortModel[0];
-
- const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`;
- dispatch(fetch({ limit: perPage, page, query }));
- };
-
- useEffect(() => {
- if (activitiesNotify.showNotification) {
- notify(activitiesNotify.typeNotification, activitiesNotify.textNotification);
- }
- }, [activitiesNotify.showNotification]);
-
- useEffect(() => {
- if (!currentUser) return;
- loadData();
- }, [sortModel, currentUser]);
-
- useEffect(() => {
- if (refetch) {
- loadData(0);
- dispatch(setRefetch(false));
- }
- }, [refetch, dispatch]);
-
- const [isModalInfoActive, setIsModalInfoActive] = useState(false)
- const [isModalTrashActive, setIsModalTrashActive] = useState(false)
-
- const handleModalAction = () => {
- setIsModalInfoActive(false)
- setIsModalTrashActive(false)
- }
-
-
-
-
- const handleCreateEventAction = ({ start, end }: SlotInfo) => {
- router.push(
- `/activities/activities-new?dateRangeStart=${start.toISOString()}&dateRangeEnd=${end.toISOString()}`,
- );
- };
-
-
- const handleDeleteModalAction = (id: string) => {
- setId(id)
- setIsModalTrashActive(true)
- }
- const handleDeleteAction = async () => {
- if (id) {
- await dispatch(deleteItem(id));
- await loadData(0);
- setIsModalTrashActive(false);
- }
- };
-
- const generateFilterRequests = useMemo(() => {
- let request = '&';
- filterItems.forEach((item) => {
- const isRangeFilter = filters.find(
- (filter) =>
- filter.title === item.fields.selectedField &&
- (filter.number || filter.date),
- );
-
- if (isRangeFilter) {
- const from = item.fields.filterValueFrom;
- const to = item.fields.filterValueTo;
- if (from) {
- request += `${item.fields.selectedField}Range=${from}&`;
- }
- if (to) {
- request += `${item.fields.selectedField}Range=${to}&`;
- }
- } else {
- const value = item.fields.filterValue;
- if (value) {
- request += `${item.fields.selectedField}=${value}&`;
- }
- }
- });
- return request;
- }, [filterItems, filters]);
-
- const deleteFilter = (value) => {
- const newItems = filterItems.filter((item) => item.id !== value);
-
- if (newItems.length) {
- setFilterItems(newItems);
- } else {
- loadData(0, '');
-
- setFilterItems(newItems);
- }
- };
-
- const handleSubmit = () => {
- loadData(0, generateFilterRequests);
-
- };
-
- const handleChange = (id) => (e) => {
- const value = e.target.value;
- const name = e.target.name;
-
- setFilterItems(
- filterItems.map((item) => {
- if (item.id !== id) return item;
- if (name === 'selectedField') return { id, fields: { [name]: value } };
-
- return { id, fields: { ...item.fields, [name]: value } }
- }),
- );
- };
-
- const handleReset = () => {
- setFilterItems([]);
- loadData(0, '');
-
- };
-
- const onPageChange = (page: number) => {
- loadData(page);
- setCurrentPage(page);
- };
-
-
- useEffect(() => {
- if (!currentUser) return;
-
- loadColumns(
- handleDeleteModalAction,
- `activities`,
- currentUser,
- ).then((newCols) => setColumns(newCols));
- }, [currentUser]);
-
-
-
- const handleTableSubmit = async (id: string, data) => {
-
- if (!_.isEmpty(data)) {
- await dispatch(update({ id, data }))
- .unwrap()
- .then((res) => res)
- .catch((err) => {
- throw new Error(err);
- });
- }
- };
-
- const onDeleteRows = async (selectedRows) => {
- await dispatch(deleteItemsByIds(selectedRows));
- await loadData(0);
- };
-
- const controlClasses =
- 'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' +
- ` ${bgColor} ${focusRing} ${corners} ` +
- 'dark:bg-slate-800 border';
-
-
- const dataGrid = (
-
- `datagrid--row`}
- rows={activities ?? []}
- columns={columns}
- initialState={{
- pagination: {
- paginationModel: {
- pageSize: 10,
- },
- },
- }}
- disableRowSelectionOnClick
- onProcessRowUpdateError={(params) => {
- console.log('Error', params);
- }}
- processRowUpdate={async (newRow, oldRow) => {
- const data = dataFormatter.dataGridEditFormatter(newRow);
-
- try {
- await handleTableSubmit(newRow.id, data);
- return newRow;
- } catch {
- return oldRow;
- }
- }}
- sortingMode={'server'}
- checkboxSelection
- onRowSelectionModelChange={(ids) => {
- setSelectedRows(ids)
- }}
- onSortModelChange={(params) => {
- params.length
- ? setSortModel(params)
- : setSortModel([{ field: '', sort: 'desc' }]);
- }}
- rowCount={count}
- pageSizeOptions={[10]}
- paginationMode={'server'}
- loading={loading}
- onPaginationModelChange={(params) => {
- onPageChange(params.page);
- }}
- />
-
- )
-
- return (
- <>
- {filterItems && Array.isArray( filterItems ) && filterItems.length ?
-
- null}
- >
-
-
- : null
- }
-
- Are you sure you want to delete this item?
-
-
-
- {!showGrid && (
- {
- loadData(0,`&calendarStart=${range.start}&calendarEnd=${range.end}`);
- }}
- entityName={'activities'}
- />
- )}
-
-
-
- {showGrid && dataGrid}
-
-
- {selectedRows.length > 0 &&
- createPortal(
- onDeleteRows(selectedRows)}
- />,
- document.getElementById('delete-rows-button'),
- )}
-
- >
- )
-}
-
-export default TableSampleActivities
diff --git a/frontend/src/components/Activities/configureActivitiesCols.tsx b/frontend/src/components/Activities/configureActivitiesCols.tsx
deleted file mode 100644
index 7454372..0000000
--- a/frontend/src/components/Activities/configureActivitiesCols.tsx
+++ /dev/null
@@ -1,333 +0,0 @@
-import React from 'react';
-import BaseIcon from '../BaseIcon';
-import { mdiEye, mdiTrashCan, mdiPencilOutline } from '@mdi/js';
-import axios from 'axios';
-import {
- GridActionsCellItem,
- GridRowParams,
- GridValueGetterParams,
-} from '@mui/x-data-grid';
-import ImageField from '../ImageField';
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter'
-import DataGridMultiSelect from "../DataGridMultiSelect";
-import ListActionsPopover from '../ListActionsPopover';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-type Params = (id: string) => void;
-
-export const loadColumns = async (
- onDelete: Params,
- entityName: string,
-
- user
-
-) => {
- async function callOptionsApi(entityName: string) {
-
- if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
-
- try {
- const data = await axios(`/${entityName}/autocomplete?limit=100`);
- return data.data;
- } catch (error) {
- console.log(error);
- return [];
- }
- }
-
- const hasUpdatePermission = hasPermission(user, 'UPDATE_ACTIVITIES')
-
- return [
-
- {
- field: 'activity_type',
- headerName: 'ActivityType',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'subject',
- headerName: 'Subject',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'details',
- headerName: 'Details',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'owner',
- headerName: 'Owner',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('users'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'lead',
- headerName: 'Lead',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('leads'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'deal',
- headerName: 'Deal',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('deals'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'contact',
- headerName: 'Contact',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('contacts'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'account',
- headerName: 'Account',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('accounts'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'activity_at',
- headerName: 'ActivityAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.activity_at),
-
- },
-
- {
- field: 'due_at',
- headerName: 'DueAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.due_at),
-
- },
-
- {
- field: 'completed_at',
- headerName: 'CompletedAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.completed_at),
-
- },
-
- {
- field: 'status',
- headerName: 'Status',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'priority',
- headerName: 'Priority',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'attachments',
- headerName: 'Attachments',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
- editable: false,
- sortable: false,
- renderCell: (params: GridValueGetterParams) => (
- <>
- {dataFormatter.filesFormatter(params.row.attachments).map(link => (
-
- ))}
- >
- ),
-
- },
-
- {
- field: 'actions',
- type: 'actions',
- minWidth: 30,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
- getActions: (params: GridRowParams) => {
-
- return [
-
-
-
,
- ]
- },
- },
- ];
-};
diff --git a/frontend/src/components/AsideMenuLayer.tsx b/frontend/src/components/AsideMenuLayer.tsx
index 3fc07a8..6c7a95e 100644
--- a/frontend/src/components/AsideMenuLayer.tsx
+++ b/frontend/src/components/AsideMenuLayer.tsx
@@ -39,7 +39,7 @@ export default function AsideMenuLayer({ menu, className = '', ...props }: Props
>
- Sales Pipeline CRM
+ Coaching SaaS Workspace
diff --git a/frontend/src/components/Contacts/CardContacts.tsx b/frontend/src/components/Contacts/CardContacts.tsx
deleted file mode 100644
index 957376d..0000000
--- a/frontend/src/components/Contacts/CardContacts.tsx
+++ /dev/null
@@ -1,231 +0,0 @@
-import React from 'react';
-import ImageField from '../ImageField';
-import ListActionsPopover from '../ListActionsPopover';
-import { useAppSelector } from '../../stores/hooks';
-import dataFormatter from '../../helpers/dataFormatter';
-import { Pagination } from '../Pagination';
-import {saveFile} from "../../helpers/fileSaver";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- contacts: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const CardContacts = ({
- contacts,
- loading,
- onDelete,
- currentPage,
- numPages,
- onPageChange,
-}: Props) => {
- const asideScrollbarsStyle = useAppSelector(
- (state) => state.style.asideScrollbarsStyle,
- );
- const bgColor = useAppSelector((state) => state.style.cardsColor);
- const darkMode = useAppSelector((state) => state.style.darkMode);
- const corners = useAppSelector((state) => state.style.corners);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_CONTACTS')
-
-
- return (
-
- {loading &&
}
-
- {!loading && contacts.map((item, index) => (
- -
-
-
-
-
- {item.full_name}
-
-
-
-
-
-
-
-
-
-
-
-
- FullName
-
-
-
- { item.full_name }
-
-
-
-
-
-
-
-
-
- Email
-
-
-
- { item.email }
-
-
-
-
-
-
-
-
-
- Phone
-
-
-
- { item.phone }
-
-
-
-
-
-
-
-
-
- JobTitle
-
-
-
- { item.job_title }
-
-
-
-
-
-
-
-
-
- Account
-
-
-
- { dataFormatter.accountsOneListFormatter(item.account) }
-
-
-
-
-
-
-
-
-
- Owner
-
-
-
- { dataFormatter.usersOneListFormatter(item.owner) }
-
-
-
-
-
-
-
-
-
- ContactStatus
-
-
-
- { item.contact_status }
-
-
-
-
-
-
-
-
-
- LinkedInURL
-
-
-
- { item.linkedin_url }
-
-
-
-
-
-
-
-
-
- Notes
-
-
-
- { item.notes }
-
-
-
-
-
-
-
-
-
- LastContactedAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_contacted_at) }
-
-
-
-
-
-
-
-
-
- NextFollow-upAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
-
-
-
-
-
-
-
-
- ))}
- {!loading && contacts.length === 0 && (
-
- )}
-
-
-
- );
-};
-
-export default CardContacts;
diff --git a/frontend/src/components/Contacts/ListContacts.tsx b/frontend/src/components/Contacts/ListContacts.tsx
deleted file mode 100644
index ae245ae..0000000
--- a/frontend/src/components/Contacts/ListContacts.tsx
+++ /dev/null
@@ -1,168 +0,0 @@
-import React from 'react';
-import CardBox from '../CardBox';
-import ImageField from '../ImageField';
-import dataFormatter from '../../helpers/dataFormatter';
-import {saveFile} from "../../helpers/fileSaver";
-import ListActionsPopover from "../ListActionsPopover";
-import {useAppSelector} from "../../stores/hooks";
-import {Pagination} from "../Pagination";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- contacts: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const ListContacts = ({ contacts, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_CONTACTS')
-
- const corners = useAppSelector((state) => state.style.corners);
- const bgColor = useAppSelector((state) => state.style.cardsColor);
-
-
- return (
- <>
-
- {loading &&
}
- {!loading && contacts.map((item) => (
-
-
-
-
-
dark:divide-dark-700 overflow-x-auto'
- }
- >
-
-
-
-
FullName
-
{ item.full_name }
-
-
-
-
-
-
-
Email
-
{ item.email }
-
-
-
-
-
-
-
Phone
-
{ item.phone }
-
-
-
-
-
-
-
JobTitle
-
{ item.job_title }
-
-
-
-
-
-
-
Account
-
{ dataFormatter.accountsOneListFormatter(item.account) }
-
-
-
-
-
-
-
Owner
-
{ dataFormatter.usersOneListFormatter(item.owner) }
-
-
-
-
-
-
-
ContactStatus
-
{ item.contact_status }
-
-
-
-
-
-
-
LinkedInURL
-
{ item.linkedin_url }
-
-
-
-
-
-
-
Notes
-
{ item.notes }
-
-
-
-
-
-
-
LastContactedAt
-
{ dataFormatter.dateTimeFormatter(item.last_contacted_at) }
-
-
-
-
-
-
-
NextFollow-upAt
-
{ dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
-
-
-
-
-
-
-
-
-
- ))}
- {!loading && contacts.length === 0 && (
-
- )}
-
-
- >
- )
-};
-
-export default ListContacts
\ No newline at end of file
diff --git a/frontend/src/components/Contacts/TableContacts.tsx b/frontend/src/components/Contacts/TableContacts.tsx
deleted file mode 100644
index 2cb1152..0000000
--- a/frontend/src/components/Contacts/TableContacts.tsx
+++ /dev/null
@@ -1,463 +0,0 @@
-import React, { useEffect, useState, useMemo } from 'react'
-import { createPortal } from 'react-dom';
-import { ToastContainer, toast } from 'react-toastify';
-import BaseButton from '../BaseButton'
-import CardBoxModal from '../CardBoxModal'
-import CardBox from "../CardBox";
-import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/contacts/contactsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import { Field, Form, Formik } from "formik";
-import {
- DataGrid,
- GridColDef,
-} from '@mui/x-data-grid';
-import {loadColumns} from "./configureContactsCols";
-import _ from 'lodash';
-import dataFormatter from '../../helpers/dataFormatter'
-import {dataGridStyles} from "../../styles";
-
-
-
-const perPage = 10
-
-const TableSampleContacts = ({ filterItems, setFilterItems, filters, showGrid }) => {
- const notify = (type, msg) => toast( msg, {type, position: "bottom-center"});
-
- const dispatch = useAppDispatch();
- const router = useRouter();
-
- const pagesList = [];
- const [id, setId] = useState(null);
- const [currentPage, setCurrentPage] = useState(0);
- const [filterRequest, setFilterRequest] = React.useState('');
- const [columns, setColumns] = useState([]);
- const [selectedRows, setSelectedRows] = useState([]);
- const [sortModel, setSortModel] = useState([
- {
- field: '',
- sort: 'desc',
- },
- ]);
-
- const { contacts, loading, count, notify: contactsNotify, refetch } = useAppSelector((state) => state.contacts)
- const { currentUser } = useAppSelector((state) => state.auth);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
- const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
- const corners = useAppSelector((state) => state.style.corners);
- const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
- for (let i = 0; i < numPages; i++) {
- pagesList.push(i);
- }
-
- const loadData = async (page = currentPage, request = filterRequest) => {
- if (page !== currentPage) setCurrentPage(page);
- if (request !== filterRequest) setFilterRequest(request);
- const { sort, field } = sortModel[0];
-
- const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`;
- dispatch(fetch({ limit: perPage, page, query }));
- };
-
- useEffect(() => {
- if (contactsNotify.showNotification) {
- notify(contactsNotify.typeNotification, contactsNotify.textNotification);
- }
- }, [contactsNotify.showNotification]);
-
- useEffect(() => {
- if (!currentUser) return;
- loadData();
- }, [sortModel, currentUser]);
-
- useEffect(() => {
- if (refetch) {
- loadData(0);
- dispatch(setRefetch(false));
- }
- }, [refetch, dispatch]);
-
- const [isModalInfoActive, setIsModalInfoActive] = useState(false)
- const [isModalTrashActive, setIsModalTrashActive] = useState(false)
-
- const handleModalAction = () => {
- setIsModalInfoActive(false)
- setIsModalTrashActive(false)
- }
-
-
-
-
-
- const handleDeleteModalAction = (id: string) => {
- setId(id)
- setIsModalTrashActive(true)
- }
- const handleDeleteAction = async () => {
- if (id) {
- await dispatch(deleteItem(id));
- await loadData(0);
- setIsModalTrashActive(false);
- }
- };
-
- const generateFilterRequests = useMemo(() => {
- let request = '&';
- filterItems.forEach((item) => {
- const isRangeFilter = filters.find(
- (filter) =>
- filter.title === item.fields.selectedField &&
- (filter.number || filter.date),
- );
-
- if (isRangeFilter) {
- const from = item.fields.filterValueFrom;
- const to = item.fields.filterValueTo;
- if (from) {
- request += `${item.fields.selectedField}Range=${from}&`;
- }
- if (to) {
- request += `${item.fields.selectedField}Range=${to}&`;
- }
- } else {
- const value = item.fields.filterValue;
- if (value) {
- request += `${item.fields.selectedField}=${value}&`;
- }
- }
- });
- return request;
- }, [filterItems, filters]);
-
- const deleteFilter = (value) => {
- const newItems = filterItems.filter((item) => item.id !== value);
-
- if (newItems.length) {
- setFilterItems(newItems);
- } else {
- loadData(0, '');
-
- setFilterItems(newItems);
- }
- };
-
- const handleSubmit = () => {
- loadData(0, generateFilterRequests);
-
- };
-
- const handleChange = (id) => (e) => {
- const value = e.target.value;
- const name = e.target.name;
-
- setFilterItems(
- filterItems.map((item) => {
- if (item.id !== id) return item;
- if (name === 'selectedField') return { id, fields: { [name]: value } };
-
- return { id, fields: { ...item.fields, [name]: value } }
- }),
- );
- };
-
- const handleReset = () => {
- setFilterItems([]);
- loadData(0, '');
-
- };
-
- const onPageChange = (page: number) => {
- loadData(page);
- setCurrentPage(page);
- };
-
-
- useEffect(() => {
- if (!currentUser) return;
-
- loadColumns(
- handleDeleteModalAction,
- `contacts`,
- currentUser,
- ).then((newCols) => setColumns(newCols));
- }, [currentUser]);
-
-
-
- const handleTableSubmit = async (id: string, data) => {
-
- if (!_.isEmpty(data)) {
- await dispatch(update({ id, data }))
- .unwrap()
- .then((res) => res)
- .catch((err) => {
- throw new Error(err);
- });
- }
- };
-
- const onDeleteRows = async (selectedRows) => {
- await dispatch(deleteItemsByIds(selectedRows));
- await loadData(0);
- };
-
- const controlClasses =
- 'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' +
- ` ${bgColor} ${focusRing} ${corners} ` +
- 'dark:bg-slate-800 border';
-
-
- const dataGrid = (
-
- `datagrid--row`}
- rows={contacts ?? []}
- columns={columns}
- initialState={{
- pagination: {
- paginationModel: {
- pageSize: 10,
- },
- },
- }}
- disableRowSelectionOnClick
- onProcessRowUpdateError={(params) => {
- console.log('Error', params);
- }}
- processRowUpdate={async (newRow, oldRow) => {
- const data = dataFormatter.dataGridEditFormatter(newRow);
-
- try {
- await handleTableSubmit(newRow.id, data);
- return newRow;
- } catch {
- return oldRow;
- }
- }}
- sortingMode={'server'}
- checkboxSelection
- onRowSelectionModelChange={(ids) => {
- setSelectedRows(ids)
- }}
- onSortModelChange={(params) => {
- params.length
- ? setSortModel(params)
- : setSortModel([{ field: '', sort: 'desc' }]);
- }}
- rowCount={count}
- pageSizeOptions={[10]}
- paginationMode={'server'}
- loading={loading}
- onPaginationModelChange={(params) => {
- onPageChange(params.page);
- }}
- />
-
- )
-
- return (
- <>
- {filterItems && Array.isArray( filterItems ) && filterItems.length ?
-
- null}
- >
-
-
- : null
- }
-
- Are you sure you want to delete this item?
-
-
-
- {dataGrid}
-
-
-
-
- {selectedRows.length > 0 &&
- createPortal(
- onDeleteRows(selectedRows)}
- />,
- document.getElementById('delete-rows-button'),
- )}
-
- >
- )
-}
-
-export default TableSampleContacts
diff --git a/frontend/src/components/Contacts/configureContactsCols.tsx b/frontend/src/components/Contacts/configureContactsCols.tsx
deleted file mode 100644
index dfb1494..0000000
--- a/frontend/src/components/Contacts/configureContactsCols.tsx
+++ /dev/null
@@ -1,253 +0,0 @@
-import React from 'react';
-import BaseIcon from '../BaseIcon';
-import { mdiEye, mdiTrashCan, mdiPencilOutline } from '@mdi/js';
-import axios from 'axios';
-import {
- GridActionsCellItem,
- GridRowParams,
- GridValueGetterParams,
-} from '@mui/x-data-grid';
-import ImageField from '../ImageField';
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter'
-import DataGridMultiSelect from "../DataGridMultiSelect";
-import ListActionsPopover from '../ListActionsPopover';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-type Params = (id: string) => void;
-
-export const loadColumns = async (
- onDelete: Params,
- entityName: string,
-
- user
-
-) => {
- async function callOptionsApi(entityName: string) {
-
- if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
-
- try {
- const data = await axios(`/${entityName}/autocomplete?limit=100`);
- return data.data;
- } catch (error) {
- console.log(error);
- return [];
- }
- }
-
- const hasUpdatePermission = hasPermission(user, 'UPDATE_CONTACTS')
-
- return [
-
- {
- field: 'full_name',
- headerName: 'FullName',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'email',
- headerName: 'Email',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'phone',
- headerName: 'Phone',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'job_title',
- headerName: 'JobTitle',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'account',
- headerName: 'Account',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('accounts'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'owner',
- headerName: 'Owner',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('users'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'contact_status',
- headerName: 'ContactStatus',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'linkedin_url',
- headerName: 'LinkedInURL',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'notes',
- headerName: 'Notes',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'last_contacted_at',
- headerName: 'LastContactedAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.last_contacted_at),
-
- },
-
- {
- field: 'next_follow_up_at',
- headerName: 'NextFollow-upAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.next_follow_up_at),
-
- },
-
- {
- field: 'actions',
- type: 'actions',
- minWidth: 30,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
- getActions: (params: GridRowParams) => {
-
- return [
-
-
-
,
- ]
- },
- },
- ];
-};
diff --git a/frontend/src/components/Deals/CardDeals.tsx b/frontend/src/components/Deals/CardDeals.tsx
deleted file mode 100644
index fb32625..0000000
--- a/frontend/src/components/Deals/CardDeals.tsx
+++ /dev/null
@@ -1,279 +0,0 @@
-import React from 'react';
-import ImageField from '../ImageField';
-import ListActionsPopover from '../ListActionsPopover';
-import { useAppSelector } from '../../stores/hooks';
-import dataFormatter from '../../helpers/dataFormatter';
-import { Pagination } from '../Pagination';
-import {saveFile} from "../../helpers/fileSaver";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- deals: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const CardDeals = ({
- deals,
- loading,
- onDelete,
- currentPage,
- numPages,
- onPageChange,
-}: Props) => {
- const asideScrollbarsStyle = useAppSelector(
- (state) => state.style.asideScrollbarsStyle,
- );
- const bgColor = useAppSelector((state) => state.style.cardsColor);
- const darkMode = useAppSelector((state) => state.style.darkMode);
- const corners = useAppSelector((state) => state.style.corners);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_DEALS')
-
-
- return (
-
- {loading &&
}
-
- {!loading && deals.map((item, index) => (
- -
-
-
-
-
- {item.name}
-
-
-
-
-
-
-
-
-
-
-
-
- DealName
-
-
-
- { item.name }
-
-
-
-
-
-
-
-
-
- Stage
-
-
-
- { dataFormatter.pipeline_stagesOneListFormatter(item.stage) }
-
-
-
-
-
-
-
-
-
- Owner
-
-
-
- { dataFormatter.usersOneListFormatter(item.owner) }
-
-
-
-
-
-
-
-
-
- Account
-
-
-
- { dataFormatter.accountsOneListFormatter(item.account) }
-
-
-
-
-
-
-
-
-
- PrimaryContact
-
-
-
- { dataFormatter.contactsOneListFormatter(item.primary_contact) }
-
-
-
-
-
-
-
-
-
- OriginatingLead
-
-
-
- { dataFormatter.leadsOneListFormatter(item.originating_lead) }
-
-
-
-
-
-
-
-
-
- Amount
-
-
-
- { item.amount }
-
-
-
-
-
-
-
-
-
- Currency
-
-
-
- { item.currency }
-
-
-
-
-
-
-
-
-
- ExpectedCloseDate
-
-
-
- { dataFormatter.dateTimeFormatter(item.expected_close_at) }
-
-
-
-
-
-
-
-
-
- ClosedDate
-
-
-
- { dataFormatter.dateTimeFormatter(item.closed_at) }
-
-
-
-
-
-
-
-
-
- DealStatus
-
-
-
- { item.deal_status }
-
-
-
-
-
-
-
-
-
- LossReason
-
-
-
- { item.loss_reason }
-
-
-
-
-
-
-
-
-
- LastActivityAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_activity_at) }
-
-
-
-
-
-
-
-
-
- NextFollow-upAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
-
-
-
-
-
-
-
-
-
- Description
-
-
-
- { item.description }
-
-
-
-
-
-
-
-
- ))}
- {!loading && deals.length === 0 && (
-
- )}
-
-
-
- );
-};
-
-export default CardDeals;
diff --git a/frontend/src/components/Deals/ListDeals.tsx b/frontend/src/components/Deals/ListDeals.tsx
deleted file mode 100644
index 6c9a675..0000000
--- a/frontend/src/components/Deals/ListDeals.tsx
+++ /dev/null
@@ -1,200 +0,0 @@
-import React from 'react';
-import CardBox from '../CardBox';
-import ImageField from '../ImageField';
-import dataFormatter from '../../helpers/dataFormatter';
-import {saveFile} from "../../helpers/fileSaver";
-import ListActionsPopover from "../ListActionsPopover";
-import {useAppSelector} from "../../stores/hooks";
-import {Pagination} from "../Pagination";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- deals: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const ListDeals = ({ deals, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_DEALS')
-
- const corners = useAppSelector((state) => state.style.corners);
- const bgColor = useAppSelector((state) => state.style.cardsColor);
-
-
- return (
- <>
-
- {loading &&
}
- {!loading && deals.map((item) => (
-
-
-
-
-
dark:divide-dark-700 overflow-x-auto'
- }
- >
-
-
-
-
DealName
-
{ item.name }
-
-
-
-
-
-
-
Stage
-
{ dataFormatter.pipeline_stagesOneListFormatter(item.stage) }
-
-
-
-
-
-
-
Owner
-
{ dataFormatter.usersOneListFormatter(item.owner) }
-
-
-
-
-
-
-
Account
-
{ dataFormatter.accountsOneListFormatter(item.account) }
-
-
-
-
-
-
-
PrimaryContact
-
{ dataFormatter.contactsOneListFormatter(item.primary_contact) }
-
-
-
-
-
-
-
OriginatingLead
-
{ dataFormatter.leadsOneListFormatter(item.originating_lead) }
-
-
-
-
-
-
-
Amount
-
{ item.amount }
-
-
-
-
-
-
-
Currency
-
{ item.currency }
-
-
-
-
-
-
-
ExpectedCloseDate
-
{ dataFormatter.dateTimeFormatter(item.expected_close_at) }
-
-
-
-
-
-
-
ClosedDate
-
{ dataFormatter.dateTimeFormatter(item.closed_at) }
-
-
-
-
-
-
-
DealStatus
-
{ item.deal_status }
-
-
-
-
-
-
-
LossReason
-
{ item.loss_reason }
-
-
-
-
-
-
-
LastActivityAt
-
{ dataFormatter.dateTimeFormatter(item.last_activity_at) }
-
-
-
-
-
-
-
NextFollow-upAt
-
{ dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
-
-
-
-
-
-
-
Description
-
{ item.description }
-
-
-
-
-
-
-
-
-
- ))}
- {!loading && deals.length === 0 && (
-
- )}
-
-
- >
- )
-};
-
-export default ListDeals
\ No newline at end of file
diff --git a/frontend/src/components/Deals/TableDeals.tsx b/frontend/src/components/Deals/TableDeals.tsx
deleted file mode 100644
index e6b860b..0000000
--- a/frontend/src/components/Deals/TableDeals.tsx
+++ /dev/null
@@ -1,506 +0,0 @@
-import React, { useEffect, useState, useMemo } from 'react'
-import { createPortal } from 'react-dom';
-import { ToastContainer, toast } from 'react-toastify';
-import BaseButton from '../BaseButton'
-import CardBoxModal from '../CardBoxModal'
-import CardBox from "../CardBox";
-import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/deals/dealsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import { Field, Form, Formik } from "formik";
-import {
- DataGrid,
- GridColDef,
-} from '@mui/x-data-grid';
-import {loadColumns} from "./configureDealsCols";
-import _ from 'lodash';
-import dataFormatter from '../../helpers/dataFormatter'
-import {dataGridStyles} from "../../styles";
-
-
-import KanbanBoard from '../KanbanBoard/KanbanBoard';
-import axios from 'axios';
-
-
-const perPage = 10
-
-const TableSampleDeals = ({ filterItems, setFilterItems, filters, showGrid }) => {
- const notify = (type, msg) => toast( msg, {type, position: "bottom-center"});
-
- const dispatch = useAppDispatch();
- const router = useRouter();
-
- const pagesList = [];
- const [id, setId] = useState(null);
- const [currentPage, setCurrentPage] = useState(0);
- const [filterRequest, setFilterRequest] = React.useState('');
- const [columns, setColumns] = useState([]);
- const [selectedRows, setSelectedRows] = useState([]);
- const [sortModel, setSortModel] = useState([
- {
- field: '',
- sort: 'desc',
- },
- ]);
-
- const [kanbanColumns, setKanbanColumns] = useState | null>(null);
- const [kanbanFilters, setKanbanFilters] = useState('');
-
- const { deals, loading, count, notify: dealsNotify, refetch } = useAppSelector((state) => state.deals)
- const { currentUser } = useAppSelector((state) => state.auth);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
- const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
- const corners = useAppSelector((state) => state.style.corners);
- const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
- for (let i = 0; i < numPages; i++) {
- pagesList.push(i);
- }
-
- const loadData = async (page = currentPage, request = filterRequest) => {
- if (page !== currentPage) setCurrentPage(page);
- if (request !== filterRequest) setFilterRequest(request);
- const { sort, field } = sortModel[0];
-
- const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`;
- dispatch(fetch({ limit: perPage, page, query }));
- };
-
- useEffect(() => {
- if (dealsNotify.showNotification) {
- notify(dealsNotify.typeNotification, dealsNotify.textNotification);
- }
- }, [dealsNotify.showNotification]);
-
- useEffect(() => {
- if (!currentUser) return;
- loadData();
- }, [sortModel, currentUser]);
-
- useEffect(() => {
- if (refetch) {
- loadData(0);
- dispatch(setRefetch(false));
- }
- }, [refetch, dispatch]);
-
- const [isModalInfoActive, setIsModalInfoActive] = useState(false)
- const [isModalTrashActive, setIsModalTrashActive] = useState(false)
-
- const handleModalAction = () => {
- setIsModalInfoActive(false)
- setIsModalTrashActive(false)
- }
-
-
- useEffect(() => {
-
-
-
-
-
- axios.get('/pipeline_stages/autocomplete?limit=100')
- .then((res) => {
- setKanbanColumns(res.data);
- })
- .catch((err) => {
- console.error('Error fetching kanban columns:', err);
- });
-
-
-
- }, []);
-
-
-
-
- const handleDeleteModalAction = (id: string) => {
- setId(id)
- setIsModalTrashActive(true)
- }
- const handleDeleteAction = async () => {
- if (id) {
- await dispatch(deleteItem(id));
- await loadData(0);
- setIsModalTrashActive(false);
- }
- };
-
- const generateFilterRequests = useMemo(() => {
- let request = '&';
- filterItems.forEach((item) => {
- const isRangeFilter = filters.find(
- (filter) =>
- filter.title === item.fields.selectedField &&
- (filter.number || filter.date),
- );
-
- if (isRangeFilter) {
- const from = item.fields.filterValueFrom;
- const to = item.fields.filterValueTo;
- if (from) {
- request += `${item.fields.selectedField}Range=${from}&`;
- }
- if (to) {
- request += `${item.fields.selectedField}Range=${to}&`;
- }
- } else {
- const value = item.fields.filterValue;
- if (value) {
- request += `${item.fields.selectedField}=${value}&`;
- }
- }
- });
- return request;
- }, [filterItems, filters]);
-
- const deleteFilter = (value) => {
- const newItems = filterItems.filter((item) => item.id !== value);
-
- if (newItems.length) {
- setFilterItems(newItems);
- } else {
- loadData(0, '');
-
- setKanbanFilters('');
-
- setFilterItems(newItems);
- }
- };
-
- const handleSubmit = () => {
- loadData(0, generateFilterRequests);
-
- setKanbanFilters(generateFilterRequests);
-
- };
-
- const handleChange = (id) => (e) => {
- const value = e.target.value;
- const name = e.target.name;
-
- setFilterItems(
- filterItems.map((item) => {
- if (item.id !== id) return item;
- if (name === 'selectedField') return { id, fields: { [name]: value } };
-
- return { id, fields: { ...item.fields, [name]: value } }
- }),
- );
- };
-
- const handleReset = () => {
- setFilterItems([]);
- loadData(0, '');
-
- setKanbanFilters('');
-
- };
-
- const onPageChange = (page: number) => {
- loadData(page);
- setCurrentPage(page);
- };
-
-
- useEffect(() => {
- if (!currentUser) return;
-
- loadColumns(
- handleDeleteModalAction,
- `deals`,
- currentUser,
- ).then((newCols) => setColumns(newCols));
- }, [currentUser]);
-
-
-
- const handleTableSubmit = async (id: string, data) => {
-
- if (!_.isEmpty(data)) {
- await dispatch(update({ id, data }))
- .unwrap()
- .then((res) => res)
- .catch((err) => {
- throw new Error(err);
- });
- }
- };
-
- const onDeleteRows = async (selectedRows) => {
- await dispatch(deleteItemsByIds(selectedRows));
- await loadData(0);
- };
-
- const controlClasses =
- 'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' +
- ` ${bgColor} ${focusRing} ${corners} ` +
- 'dark:bg-slate-800 border';
-
-
- const dataGrid = (
-
- `datagrid--row`}
- rows={deals ?? []}
- columns={columns}
- initialState={{
- pagination: {
- paginationModel: {
- pageSize: 10,
- },
- },
- }}
- disableRowSelectionOnClick
- onProcessRowUpdateError={(params) => {
- console.log('Error', params);
- }}
- processRowUpdate={async (newRow, oldRow) => {
- const data = dataFormatter.dataGridEditFormatter(newRow);
-
- try {
- await handleTableSubmit(newRow.id, data);
- return newRow;
- } catch {
- return oldRow;
- }
- }}
- sortingMode={'server'}
- checkboxSelection
- onRowSelectionModelChange={(ids) => {
- setSelectedRows(ids)
- }}
- onSortModelChange={(params) => {
- params.length
- ? setSortModel(params)
- : setSortModel([{ field: '', sort: 'desc' }]);
- }}
- rowCount={count}
- pageSizeOptions={[10]}
- paginationMode={'server'}
- loading={loading}
- onPaginationModelChange={(params) => {
- onPageChange(params.page);
- }}
- />
-
- )
-
- return (
- <>
- {filterItems && Array.isArray( filterItems ) && filterItems.length ?
-
- null}
- >
-
-
- : null
- }
-
- Are you sure you want to delete this item?
-
-
-
-
- {!showGrid && kanbanColumns && (
-
- )}
-
-
-
- {showGrid && dataGrid}
-
-
- {selectedRows.length > 0 &&
- createPortal(
- onDeleteRows(selectedRows)}
- />,
- document.getElementById('delete-rows-button'),
- )}
-
- >
- )
-}
-
-export default TableSampleDeals
diff --git a/frontend/src/components/Deals/configureDealsCols.tsx b/frontend/src/components/Deals/configureDealsCols.tsx
deleted file mode 100644
index 4610be6..0000000
--- a/frontend/src/components/Deals/configureDealsCols.tsx
+++ /dev/null
@@ -1,341 +0,0 @@
-import React from 'react';
-import BaseIcon from '../BaseIcon';
-import { mdiEye, mdiTrashCan, mdiPencilOutline } from '@mdi/js';
-import axios from 'axios';
-import {
- GridActionsCellItem,
- GridRowParams,
- GridValueGetterParams,
-} from '@mui/x-data-grid';
-import ImageField from '../ImageField';
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter'
-import DataGridMultiSelect from "../DataGridMultiSelect";
-import ListActionsPopover from '../ListActionsPopover';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-type Params = (id: string) => void;
-
-export const loadColumns = async (
- onDelete: Params,
- entityName: string,
-
- user
-
-) => {
- async function callOptionsApi(entityName: string) {
-
- if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
-
- try {
- const data = await axios(`/${entityName}/autocomplete?limit=100`);
- return data.data;
- } catch (error) {
- console.log(error);
- return [];
- }
- }
-
- const hasUpdatePermission = hasPermission(user, 'UPDATE_DEALS')
-
- return [
-
- {
- field: 'name',
- headerName: 'DealName',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'stage',
- headerName: 'Stage',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('pipeline_stages'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'owner',
- headerName: 'Owner',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('users'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'account',
- headerName: 'Account',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('accounts'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'primary_contact',
- headerName: 'PrimaryContact',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('contacts'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'originating_lead',
- headerName: 'OriginatingLead',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('leads'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'amount',
- headerName: 'Amount',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'number',
-
- },
-
- {
- field: 'currency',
- headerName: 'Currency',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'expected_close_at',
- headerName: 'ExpectedCloseDate',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.expected_close_at),
-
- },
-
- {
- field: 'closed_at',
- headerName: 'ClosedDate',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.closed_at),
-
- },
-
- {
- field: 'deal_status',
- headerName: 'DealStatus',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'loss_reason',
- headerName: 'LossReason',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'last_activity_at',
- headerName: 'LastActivityAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.last_activity_at),
-
- },
-
- {
- field: 'next_follow_up_at',
- headerName: 'NextFollow-upAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.next_follow_up_at),
-
- },
-
- {
- field: 'description',
- headerName: 'Description',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'actions',
- type: 'actions',
- minWidth: 30,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
- getActions: (params: GridRowParams) => {
-
- return [
-
-
-
,
- ]
- },
- },
- ];
-};
diff --git a/frontend/src/components/Lead_sources/CardLead_sources.tsx b/frontend/src/components/Lead_sources/CardLead_sources.tsx
deleted file mode 100644
index e161922..0000000
--- a/frontend/src/components/Lead_sources/CardLead_sources.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-import React from 'react';
-import ImageField from '../ImageField';
-import ListActionsPopover from '../ListActionsPopover';
-import { useAppSelector } from '../../stores/hooks';
-import dataFormatter from '../../helpers/dataFormatter';
-import { Pagination } from '../Pagination';
-import {saveFile} from "../../helpers/fileSaver";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- lead_sources: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const CardLead_sources = ({
- lead_sources,
- loading,
- onDelete,
- currentPage,
- numPages,
- onPageChange,
-}: Props) => {
- const asideScrollbarsStyle = useAppSelector(
- (state) => state.style.asideScrollbarsStyle,
- );
- const bgColor = useAppSelector((state) => state.style.cardsColor);
- const darkMode = useAppSelector((state) => state.style.darkMode);
- const corners = useAppSelector((state) => state.style.corners);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_LEAD_SOURCES')
-
-
- return (
-
- {loading &&
}
-
- {!loading && lead_sources.map((item, index) => (
- -
-
-
-
-
- {item.name}
-
-
-
-
-
-
-
-
-
-
-
-
- SourceName
-
-
-
- { item.name }
-
-
-
-
-
-
-
-
-
- Active
-
-
-
- { dataFormatter.booleanFormatter(item.is_active) }
-
-
-
-
-
-
-
-
-
- Description
-
-
-
- { item.description }
-
-
-
-
-
-
-
-
- ))}
- {!loading && lead_sources.length === 0 && (
-
- )}
-
-
-
- );
-};
-
-export default CardLead_sources;
diff --git a/frontend/src/components/Lead_sources/ListLead_sources.tsx b/frontend/src/components/Lead_sources/ListLead_sources.tsx
deleted file mode 100644
index 2aeaa2b..0000000
--- a/frontend/src/components/Lead_sources/ListLead_sources.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import React from 'react';
-import CardBox from '../CardBox';
-import ImageField from '../ImageField';
-import dataFormatter from '../../helpers/dataFormatter';
-import {saveFile} from "../../helpers/fileSaver";
-import ListActionsPopover from "../ListActionsPopover";
-import {useAppSelector} from "../../stores/hooks";
-import {Pagination} from "../Pagination";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- lead_sources: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const ListLead_sources = ({ lead_sources, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_LEAD_SOURCES')
-
- const corners = useAppSelector((state) => state.style.corners);
- const bgColor = useAppSelector((state) => state.style.cardsColor);
-
-
- return (
- <>
-
- {loading &&
}
- {!loading && lead_sources.map((item) => (
-
-
-
-
-
dark:divide-dark-700 overflow-x-auto'
- }
- >
-
-
-
-
SourceName
-
{ item.name }
-
-
-
-
-
-
-
Active
-
{ dataFormatter.booleanFormatter(item.is_active) }
-
-
-
-
-
-
-
Description
-
{ item.description }
-
-
-
-
-
-
-
-
-
- ))}
- {!loading && lead_sources.length === 0 && (
-
- )}
-
-
- >
- )
-};
-
-export default ListLead_sources
\ No newline at end of file
diff --git a/frontend/src/components/Lead_sources/TableLead_sources.tsx b/frontend/src/components/Lead_sources/TableLead_sources.tsx
deleted file mode 100644
index 407fcb8..0000000
--- a/frontend/src/components/Lead_sources/TableLead_sources.tsx
+++ /dev/null
@@ -1,476 +0,0 @@
-import React, { useEffect, useState, useMemo } from 'react'
-import { createPortal } from 'react-dom';
-import { ToastContainer, toast } from 'react-toastify';
-import BaseButton from '../BaseButton'
-import CardBoxModal from '../CardBoxModal'
-import CardBox from "../CardBox";
-import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/lead_sources/lead_sourcesSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import { Field, Form, Formik } from "formik";
-import {
- DataGrid,
- GridColDef,
-} from '@mui/x-data-grid';
-import {loadColumns} from "./configureLead_sourcesCols";
-import _ from 'lodash';
-import dataFormatter from '../../helpers/dataFormatter'
-import {dataGridStyles} from "../../styles";
-
-
-import ListLead_sources from './ListLead_sources';
-
-
-const perPage = 10
-
-const TableSampleLead_sources = ({ filterItems, setFilterItems, filters, showGrid }) => {
- const notify = (type, msg) => toast( msg, {type, position: "bottom-center"});
-
- const dispatch = useAppDispatch();
- const router = useRouter();
-
- const pagesList = [];
- const [id, setId] = useState(null);
- const [currentPage, setCurrentPage] = useState(0);
- const [filterRequest, setFilterRequest] = React.useState('');
- const [columns, setColumns] = useState([]);
- const [selectedRows, setSelectedRows] = useState([]);
- const [sortModel, setSortModel] = useState([
- {
- field: '',
- sort: 'desc',
- },
- ]);
-
- const { lead_sources, loading, count, notify: lead_sourcesNotify, refetch } = useAppSelector((state) => state.lead_sources)
- const { currentUser } = useAppSelector((state) => state.auth);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
- const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
- const corners = useAppSelector((state) => state.style.corners);
- const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
- for (let i = 0; i < numPages; i++) {
- pagesList.push(i);
- }
-
- const loadData = async (page = currentPage, request = filterRequest) => {
- if (page !== currentPage) setCurrentPage(page);
- if (request !== filterRequest) setFilterRequest(request);
- const { sort, field } = sortModel[0];
-
- const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`;
- dispatch(fetch({ limit: perPage, page, query }));
- };
-
- useEffect(() => {
- if (lead_sourcesNotify.showNotification) {
- notify(lead_sourcesNotify.typeNotification, lead_sourcesNotify.textNotification);
- }
- }, [lead_sourcesNotify.showNotification]);
-
- useEffect(() => {
- if (!currentUser) return;
- loadData();
- }, [sortModel, currentUser]);
-
- useEffect(() => {
- if (refetch) {
- loadData(0);
- dispatch(setRefetch(false));
- }
- }, [refetch, dispatch]);
-
- const [isModalInfoActive, setIsModalInfoActive] = useState(false)
- const [isModalTrashActive, setIsModalTrashActive] = useState(false)
-
- const handleModalAction = () => {
- setIsModalInfoActive(false)
- setIsModalTrashActive(false)
- }
-
-
-
-
-
- const handleDeleteModalAction = (id: string) => {
- setId(id)
- setIsModalTrashActive(true)
- }
- const handleDeleteAction = async () => {
- if (id) {
- await dispatch(deleteItem(id));
- await loadData(0);
- setIsModalTrashActive(false);
- }
- };
-
- const generateFilterRequests = useMemo(() => {
- let request = '&';
- filterItems.forEach((item) => {
- const isRangeFilter = filters.find(
- (filter) =>
- filter.title === item.fields.selectedField &&
- (filter.number || filter.date),
- );
-
- if (isRangeFilter) {
- const from = item.fields.filterValueFrom;
- const to = item.fields.filterValueTo;
- if (from) {
- request += `${item.fields.selectedField}Range=${from}&`;
- }
- if (to) {
- request += `${item.fields.selectedField}Range=${to}&`;
- }
- } else {
- const value = item.fields.filterValue;
- if (value) {
- request += `${item.fields.selectedField}=${value}&`;
- }
- }
- });
- return request;
- }, [filterItems, filters]);
-
- const deleteFilter = (value) => {
- const newItems = filterItems.filter((item) => item.id !== value);
-
- if (newItems.length) {
- setFilterItems(newItems);
- } else {
- loadData(0, '');
-
- setFilterItems(newItems);
- }
- };
-
- const handleSubmit = () => {
- loadData(0, generateFilterRequests);
-
- };
-
- const handleChange = (id) => (e) => {
- const value = e.target.value;
- const name = e.target.name;
-
- setFilterItems(
- filterItems.map((item) => {
- if (item.id !== id) return item;
- if (name === 'selectedField') return { id, fields: { [name]: value } };
-
- return { id, fields: { ...item.fields, [name]: value } }
- }),
- );
- };
-
- const handleReset = () => {
- setFilterItems([]);
- loadData(0, '');
-
- };
-
- const onPageChange = (page: number) => {
- loadData(page);
- setCurrentPage(page);
- };
-
-
- useEffect(() => {
- if (!currentUser) return;
-
- loadColumns(
- handleDeleteModalAction,
- `lead_sources`,
- currentUser,
- ).then((newCols) => setColumns(newCols));
- }, [currentUser]);
-
-
-
- const handleTableSubmit = async (id: string, data) => {
-
- if (!_.isEmpty(data)) {
- await dispatch(update({ id, data }))
- .unwrap()
- .then((res) => res)
- .catch((err) => {
- throw new Error(err);
- });
- }
- };
-
- const onDeleteRows = async (selectedRows) => {
- await dispatch(deleteItemsByIds(selectedRows));
- await loadData(0);
- };
-
- const controlClasses =
- 'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' +
- ` ${bgColor} ${focusRing} ${corners} ` +
- 'dark:bg-slate-800 border';
-
-
- const dataGrid = (
-
- `datagrid--row`}
- rows={lead_sources ?? []}
- columns={columns}
- initialState={{
- pagination: {
- paginationModel: {
- pageSize: 10,
- },
- },
- }}
- disableRowSelectionOnClick
- onProcessRowUpdateError={(params) => {
- console.log('Error', params);
- }}
- processRowUpdate={async (newRow, oldRow) => {
- const data = dataFormatter.dataGridEditFormatter(newRow);
-
- try {
- await handleTableSubmit(newRow.id, data);
- return newRow;
- } catch {
- return oldRow;
- }
- }}
- sortingMode={'server'}
- checkboxSelection
- onRowSelectionModelChange={(ids) => {
- setSelectedRows(ids)
- }}
- onSortModelChange={(params) => {
- params.length
- ? setSortModel(params)
- : setSortModel([{ field: '', sort: 'desc' }]);
- }}
- rowCount={count}
- pageSizeOptions={[10]}
- paginationMode={'server'}
- loading={loading}
- onPaginationModelChange={(params) => {
- onPageChange(params.page);
- }}
- />
-
- )
-
- return (
- <>
- {filterItems && Array.isArray( filterItems ) && filterItems.length ?
-
- null}
- >
-
-
- : null
- }
-
- Are you sure you want to delete this item?
-
-
-
- {lead_sources && Array.isArray(lead_sources) && !showGrid && (
-
- )}
-
-
-
- {showGrid && dataGrid}
-
-
- {selectedRows.length > 0 &&
- createPortal(
- onDeleteRows(selectedRows)}
- />,
- document.getElementById('delete-rows-button'),
- )}
-
- >
- )
-}
-
-export default TableSampleLead_sources
diff --git a/frontend/src/components/Lead_sources/configureLead_sourcesCols.tsx b/frontend/src/components/Lead_sources/configureLead_sourcesCols.tsx
deleted file mode 100644
index 69fdc76..0000000
--- a/frontend/src/components/Lead_sources/configureLead_sourcesCols.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import React from 'react';
-import BaseIcon from '../BaseIcon';
-import { mdiEye, mdiTrashCan, mdiPencilOutline } from '@mdi/js';
-import axios from 'axios';
-import {
- GridActionsCellItem,
- GridRowParams,
- GridValueGetterParams,
-} from '@mui/x-data-grid';
-import ImageField from '../ImageField';
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter'
-import DataGridMultiSelect from "../DataGridMultiSelect";
-import ListActionsPopover from '../ListActionsPopover';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-type Params = (id: string) => void;
-
-export const loadColumns = async (
- onDelete: Params,
- entityName: string,
-
- user
-
-) => {
- async function callOptionsApi(entityName: string) {
-
- if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
-
- try {
- const data = await axios(`/${entityName}/autocomplete?limit=100`);
- return data.data;
- } catch (error) {
- console.log(error);
- return [];
- }
- }
-
- const hasUpdatePermission = hasPermission(user, 'UPDATE_LEAD_SOURCES')
-
- return [
-
- {
- field: 'name',
- headerName: 'SourceName',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'is_active',
- headerName: 'Active',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'boolean',
-
- },
-
- {
- field: 'description',
- headerName: 'Description',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'actions',
- type: 'actions',
- minWidth: 30,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
- getActions: (params: GridRowParams) => {
-
- return [
-
-
-
,
- ]
- },
- },
- ];
-};
diff --git a/frontend/src/components/Leads/CardLeads.tsx b/frontend/src/components/Leads/CardLeads.tsx
deleted file mode 100644
index 3279cb9..0000000
--- a/frontend/src/components/Leads/CardLeads.tsx
+++ /dev/null
@@ -1,255 +0,0 @@
-import React from 'react';
-import ImageField from '../ImageField';
-import ListActionsPopover from '../ListActionsPopover';
-import { useAppSelector } from '../../stores/hooks';
-import dataFormatter from '../../helpers/dataFormatter';
-import { Pagination } from '../Pagination';
-import {saveFile} from "../../helpers/fileSaver";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- leads: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const CardLeads = ({
- leads,
- loading,
- onDelete,
- currentPage,
- numPages,
- onPageChange,
-}: Props) => {
- const asideScrollbarsStyle = useAppSelector(
- (state) => state.style.asideScrollbarsStyle,
- );
- const bgColor = useAppSelector((state) => state.style.cardsColor);
- const darkMode = useAppSelector((state) => state.style.darkMode);
- const corners = useAppSelector((state) => state.style.corners);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_LEADS')
-
-
- return (
-
- {loading &&
}
-
- {!loading && leads.map((item, index) => (
- -
-
-
-
-
- {item.lead_name}
-
-
-
-
-
-
-
-
-
-
-
-
- LeadName
-
-
-
- { item.lead_name }
-
-
-
-
-
-
-
-
-
- CompanyName
-
-
-
- { item.company_name }
-
-
-
-
-
-
-
-
-
- Email
-
-
-
- { item.email }
-
-
-
-
-
-
-
-
-
- Phone
-
-
-
- { item.phone }
-
-
-
-
-
-
-
-
-
- Owner
-
-
-
- { dataFormatter.usersOneListFormatter(item.owner) }
-
-
-
-
-
-
-
-
-
- Source
-
-
-
- { dataFormatter.lead_sourcesOneListFormatter(item.source) }
-
-
-
-
-
-
-
-
-
- LeadStatus
-
-
-
- { item.lead_status }
-
-
-
-
-
-
-
-
-
- LeadRating
-
-
-
- { item.lead_rating }
-
-
-
-
-
-
-
-
-
- Notes
-
-
-
- { item.notes }
-
-
-
-
-
-
-
-
-
- LastContactedAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_contacted_at) }
-
-
-
-
-
-
-
-
-
- NextFollow-upAt
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
-
-
-
-
-
-
-
-
-
- LinkedAccount
-
-
-
- { dataFormatter.accountsOneListFormatter(item.account) }
-
-
-
-
-
-
-
-
-
- PrimaryContact
-
-
-
- { dataFormatter.contactsOneListFormatter(item.primary_contact) }
-
-
-
-
-
-
-
-
- ))}
- {!loading && leads.length === 0 && (
-
- )}
-
-
-
- );
-};
-
-export default CardLeads;
diff --git a/frontend/src/components/Leads/ListLeads.tsx b/frontend/src/components/Leads/ListLeads.tsx
deleted file mode 100644
index cd26365..0000000
--- a/frontend/src/components/Leads/ListLeads.tsx
+++ /dev/null
@@ -1,184 +0,0 @@
-import React from 'react';
-import CardBox from '../CardBox';
-import ImageField from '../ImageField';
-import dataFormatter from '../../helpers/dataFormatter';
-import {saveFile} from "../../helpers/fileSaver";
-import ListActionsPopover from "../ListActionsPopover";
-import {useAppSelector} from "../../stores/hooks";
-import {Pagination} from "../Pagination";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- leads: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const ListLeads = ({ leads, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_LEADS')
-
- const corners = useAppSelector((state) => state.style.corners);
- const bgColor = useAppSelector((state) => state.style.cardsColor);
-
-
- return (
- <>
-
- {loading &&
}
- {!loading && leads.map((item) => (
-
-
-
-
-
dark:divide-dark-700 overflow-x-auto'
- }
- >
-
-
-
-
LeadName
-
{ item.lead_name }
-
-
-
-
-
-
-
CompanyName
-
{ item.company_name }
-
-
-
-
-
-
-
Email
-
{ item.email }
-
-
-
-
-
-
-
Phone
-
{ item.phone }
-
-
-
-
-
-
-
Owner
-
{ dataFormatter.usersOneListFormatter(item.owner) }
-
-
-
-
-
-
-
Source
-
{ dataFormatter.lead_sourcesOneListFormatter(item.source) }
-
-
-
-
-
-
-
LeadStatus
-
{ item.lead_status }
-
-
-
-
-
-
-
LeadRating
-
{ item.lead_rating }
-
-
-
-
-
-
-
Notes
-
{ item.notes }
-
-
-
-
-
-
-
LastContactedAt
-
{ dataFormatter.dateTimeFormatter(item.last_contacted_at) }
-
-
-
-
-
-
-
NextFollow-upAt
-
{ dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
-
-
-
-
-
-
-
LinkedAccount
-
{ dataFormatter.accountsOneListFormatter(item.account) }
-
-
-
-
-
-
-
PrimaryContact
-
{ dataFormatter.contactsOneListFormatter(item.primary_contact) }
-
-
-
-
-
-
-
-
-
- ))}
- {!loading && leads.length === 0 && (
-
- )}
-
-
- >
- )
-};
-
-export default ListLeads
\ No newline at end of file
diff --git a/frontend/src/components/Leads/TableLeads.tsx b/frontend/src/components/Leads/TableLeads.tsx
deleted file mode 100644
index de522f1..0000000
--- a/frontend/src/components/Leads/TableLeads.tsx
+++ /dev/null
@@ -1,463 +0,0 @@
-import React, { useEffect, useState, useMemo } from 'react'
-import { createPortal } from 'react-dom';
-import { ToastContainer, toast } from 'react-toastify';
-import BaseButton from '../BaseButton'
-import CardBoxModal from '../CardBoxModal'
-import CardBox from "../CardBox";
-import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/leads/leadsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import { Field, Form, Formik } from "formik";
-import {
- DataGrid,
- GridColDef,
-} from '@mui/x-data-grid';
-import {loadColumns} from "./configureLeadsCols";
-import _ from 'lodash';
-import dataFormatter from '../../helpers/dataFormatter'
-import {dataGridStyles} from "../../styles";
-
-
-
-const perPage = 10
-
-const TableSampleLeads = ({ filterItems, setFilterItems, filters, showGrid }) => {
- const notify = (type, msg) => toast( msg, {type, position: "bottom-center"});
-
- const dispatch = useAppDispatch();
- const router = useRouter();
-
- const pagesList = [];
- const [id, setId] = useState(null);
- const [currentPage, setCurrentPage] = useState(0);
- const [filterRequest, setFilterRequest] = React.useState('');
- const [columns, setColumns] = useState([]);
- const [selectedRows, setSelectedRows] = useState([]);
- const [sortModel, setSortModel] = useState([
- {
- field: '',
- sort: 'desc',
- },
- ]);
-
- const { leads, loading, count, notify: leadsNotify, refetch } = useAppSelector((state) => state.leads)
- const { currentUser } = useAppSelector((state) => state.auth);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
- const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
- const corners = useAppSelector((state) => state.style.corners);
- const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
- for (let i = 0; i < numPages; i++) {
- pagesList.push(i);
- }
-
- const loadData = async (page = currentPage, request = filterRequest) => {
- if (page !== currentPage) setCurrentPage(page);
- if (request !== filterRequest) setFilterRequest(request);
- const { sort, field } = sortModel[0];
-
- const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`;
- dispatch(fetch({ limit: perPage, page, query }));
- };
-
- useEffect(() => {
- if (leadsNotify.showNotification) {
- notify(leadsNotify.typeNotification, leadsNotify.textNotification);
- }
- }, [leadsNotify.showNotification]);
-
- useEffect(() => {
- if (!currentUser) return;
- loadData();
- }, [sortModel, currentUser]);
-
- useEffect(() => {
- if (refetch) {
- loadData(0);
- dispatch(setRefetch(false));
- }
- }, [refetch, dispatch]);
-
- const [isModalInfoActive, setIsModalInfoActive] = useState(false)
- const [isModalTrashActive, setIsModalTrashActive] = useState(false)
-
- const handleModalAction = () => {
- setIsModalInfoActive(false)
- setIsModalTrashActive(false)
- }
-
-
-
-
-
- const handleDeleteModalAction = (id: string) => {
- setId(id)
- setIsModalTrashActive(true)
- }
- const handleDeleteAction = async () => {
- if (id) {
- await dispatch(deleteItem(id));
- await loadData(0);
- setIsModalTrashActive(false);
- }
- };
-
- const generateFilterRequests = useMemo(() => {
- let request = '&';
- filterItems.forEach((item) => {
- const isRangeFilter = filters.find(
- (filter) =>
- filter.title === item.fields.selectedField &&
- (filter.number || filter.date),
- );
-
- if (isRangeFilter) {
- const from = item.fields.filterValueFrom;
- const to = item.fields.filterValueTo;
- if (from) {
- request += `${item.fields.selectedField}Range=${from}&`;
- }
- if (to) {
- request += `${item.fields.selectedField}Range=${to}&`;
- }
- } else {
- const value = item.fields.filterValue;
- if (value) {
- request += `${item.fields.selectedField}=${value}&`;
- }
- }
- });
- return request;
- }, [filterItems, filters]);
-
- const deleteFilter = (value) => {
- const newItems = filterItems.filter((item) => item.id !== value);
-
- if (newItems.length) {
- setFilterItems(newItems);
- } else {
- loadData(0, '');
-
- setFilterItems(newItems);
- }
- };
-
- const handleSubmit = () => {
- loadData(0, generateFilterRequests);
-
- };
-
- const handleChange = (id) => (e) => {
- const value = e.target.value;
- const name = e.target.name;
-
- setFilterItems(
- filterItems.map((item) => {
- if (item.id !== id) return item;
- if (name === 'selectedField') return { id, fields: { [name]: value } };
-
- return { id, fields: { ...item.fields, [name]: value } }
- }),
- );
- };
-
- const handleReset = () => {
- setFilterItems([]);
- loadData(0, '');
-
- };
-
- const onPageChange = (page: number) => {
- loadData(page);
- setCurrentPage(page);
- };
-
-
- useEffect(() => {
- if (!currentUser) return;
-
- loadColumns(
- handleDeleteModalAction,
- `leads`,
- currentUser,
- ).then((newCols) => setColumns(newCols));
- }, [currentUser]);
-
-
-
- const handleTableSubmit = async (id: string, data) => {
-
- if (!_.isEmpty(data)) {
- await dispatch(update({ id, data }))
- .unwrap()
- .then((res) => res)
- .catch((err) => {
- throw new Error(err);
- });
- }
- };
-
- const onDeleteRows = async (selectedRows) => {
- await dispatch(deleteItemsByIds(selectedRows));
- await loadData(0);
- };
-
- const controlClasses =
- 'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' +
- ` ${bgColor} ${focusRing} ${corners} ` +
- 'dark:bg-slate-800 border';
-
-
- const dataGrid = (
-
- `datagrid--row`}
- rows={leads ?? []}
- columns={columns}
- initialState={{
- pagination: {
- paginationModel: {
- pageSize: 10,
- },
- },
- }}
- disableRowSelectionOnClick
- onProcessRowUpdateError={(params) => {
- console.log('Error', params);
- }}
- processRowUpdate={async (newRow, oldRow) => {
- const data = dataFormatter.dataGridEditFormatter(newRow);
-
- try {
- await handleTableSubmit(newRow.id, data);
- return newRow;
- } catch {
- return oldRow;
- }
- }}
- sortingMode={'server'}
- checkboxSelection
- onRowSelectionModelChange={(ids) => {
- setSelectedRows(ids)
- }}
- onSortModelChange={(params) => {
- params.length
- ? setSortModel(params)
- : setSortModel([{ field: '', sort: 'desc' }]);
- }}
- rowCount={count}
- pageSizeOptions={[10]}
- paginationMode={'server'}
- loading={loading}
- onPaginationModelChange={(params) => {
- onPageChange(params.page);
- }}
- />
-
- )
-
- return (
- <>
- {filterItems && Array.isArray( filterItems ) && filterItems.length ?
-
- null}
- >
-
-
- : null
- }
-
- Are you sure you want to delete this item?
-
-
-
- {dataGrid}
-
-
-
-
- {selectedRows.length > 0 &&
- createPortal(
- onDeleteRows(selectedRows)}
- />,
- document.getElementById('delete-rows-button'),
- )}
-
- >
- )
-}
-
-export default TableSampleLeads
diff --git a/frontend/src/components/Leads/configureLeadsCols.tsx b/frontend/src/components/Leads/configureLeadsCols.tsx
deleted file mode 100644
index eb91efa..0000000
--- a/frontend/src/components/Leads/configureLeadsCols.tsx
+++ /dev/null
@@ -1,297 +0,0 @@
-import React from 'react';
-import BaseIcon from '../BaseIcon';
-import { mdiEye, mdiTrashCan, mdiPencilOutline } from '@mdi/js';
-import axios from 'axios';
-import {
- GridActionsCellItem,
- GridRowParams,
- GridValueGetterParams,
-} from '@mui/x-data-grid';
-import ImageField from '../ImageField';
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter'
-import DataGridMultiSelect from "../DataGridMultiSelect";
-import ListActionsPopover from '../ListActionsPopover';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-type Params = (id: string) => void;
-
-export const loadColumns = async (
- onDelete: Params,
- entityName: string,
-
- user
-
-) => {
- async function callOptionsApi(entityName: string) {
-
- if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
-
- try {
- const data = await axios(`/${entityName}/autocomplete?limit=100`);
- return data.data;
- } catch (error) {
- console.log(error);
- return [];
- }
- }
-
- const hasUpdatePermission = hasPermission(user, 'UPDATE_LEADS')
-
- return [
-
- {
- field: 'lead_name',
- headerName: 'LeadName',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'company_name',
- headerName: 'CompanyName',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'email',
- headerName: 'Email',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'phone',
- headerName: 'Phone',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'owner',
- headerName: 'Owner',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('users'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'source',
- headerName: 'Source',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('lead_sources'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'lead_status',
- headerName: 'LeadStatus',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'lead_rating',
- headerName: 'LeadRating',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'notes',
- headerName: 'Notes',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'last_contacted_at',
- headerName: 'LastContactedAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.last_contacted_at),
-
- },
-
- {
- field: 'next_follow_up_at',
- headerName: 'NextFollow-upAt',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'dateTime',
- valueGetter: (params: GridValueGetterParams) =>
- new Date(params.row.next_follow_up_at),
-
- },
-
- {
- field: 'account',
- headerName: 'LinkedAccount',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('accounts'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'primary_contact',
- headerName: 'PrimaryContact',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- sortable: false,
- type: 'singleSelect',
- getOptionValue: (value: any) => value?.id,
- getOptionLabel: (value: any) => value?.label,
- valueOptions: await callOptionsApi('contacts'),
- valueGetter: (params: GridValueGetterParams) =>
- params?.value?.id ?? params?.value,
-
- },
-
- {
- field: 'actions',
- type: 'actions',
- minWidth: 30,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
- getActions: (params: GridRowParams) => {
-
- return [
-
-
-
,
- ]
- },
- },
- ];
-};
diff --git a/frontend/src/components/Pipeline_stages/CardPipeline_stages.tsx b/frontend/src/components/Pipeline_stages/CardPipeline_stages.tsx
deleted file mode 100644
index d46edfc..0000000
--- a/frontend/src/components/Pipeline_stages/CardPipeline_stages.tsx
+++ /dev/null
@@ -1,171 +0,0 @@
-import React from 'react';
-import ImageField from '../ImageField';
-import ListActionsPopover from '../ListActionsPopover';
-import { useAppSelector } from '../../stores/hooks';
-import dataFormatter from '../../helpers/dataFormatter';
-import { Pagination } from '../Pagination';
-import {saveFile} from "../../helpers/fileSaver";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- pipeline_stages: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const CardPipeline_stages = ({
- pipeline_stages,
- loading,
- onDelete,
- currentPage,
- numPages,
- onPageChange,
-}: Props) => {
- const asideScrollbarsStyle = useAppSelector(
- (state) => state.style.asideScrollbarsStyle,
- );
- const bgColor = useAppSelector((state) => state.style.cardsColor);
- const darkMode = useAppSelector((state) => state.style.darkMode);
- const corners = useAppSelector((state) => state.style.corners);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_PIPELINE_STAGES')
-
-
- return (
-
- {loading &&
}
-
- {!loading && pipeline_stages.map((item, index) => (
- -
-
-
-
-
- {item.name}
-
-
-
-
-
-
-
-
-
-
-
-
- StageName
-
-
-
- { item.name }
-
-
-
-
-
-
-
-
-
- SortOrder
-
-
-
- { item.sort_order }
-
-
-
-
-
-
-
-
-
- WinProbability
-
-
-
- { item.win_probability }
-
-
-
-
-
-
-
-
-
- IsWon
-
-
-
- { dataFormatter.booleanFormatter(item.is_won) }
-
-
-
-
-
-
-
-
-
- IsLost
-
-
-
- { dataFormatter.booleanFormatter(item.is_lost) }
-
-
-
-
-
-
-
-
-
- Active
-
-
-
- { dataFormatter.booleanFormatter(item.is_active) }
-
-
-
-
-
-
-
-
- ))}
- {!loading && pipeline_stages.length === 0 && (
-
- )}
-
-
-
- );
-};
-
-export default CardPipeline_stages;
diff --git a/frontend/src/components/Pipeline_stages/ListPipeline_stages.tsx b/frontend/src/components/Pipeline_stages/ListPipeline_stages.tsx
deleted file mode 100644
index 804fca7..0000000
--- a/frontend/src/components/Pipeline_stages/ListPipeline_stages.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-import React from 'react';
-import CardBox from '../CardBox';
-import ImageField from '../ImageField';
-import dataFormatter from '../../helpers/dataFormatter';
-import {saveFile} from "../../helpers/fileSaver";
-import ListActionsPopover from "../ListActionsPopover";
-import {useAppSelector} from "../../stores/hooks";
-import {Pagination} from "../Pagination";
-import LoadingSpinner from "../LoadingSpinner";
-import Link from 'next/link';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-type Props = {
- pipeline_stages: any[];
- loading: boolean;
- onDelete: (id: string) => void;
- currentPage: number;
- numPages: number;
- onPageChange: (page: number) => void;
-};
-
-const ListPipeline_stages = ({ pipeline_stages, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
-
- const currentUser = useAppSelector((state) => state.auth.currentUser);
- const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_PIPELINE_STAGES')
-
- const corners = useAppSelector((state) => state.style.corners);
- const bgColor = useAppSelector((state) => state.style.cardsColor);
-
-
- return (
- <>
-
- {loading &&
}
- {!loading && pipeline_stages.map((item) => (
-
-
-
-
-
dark:divide-dark-700 overflow-x-auto'
- }
- >
-
-
-
-
StageName
-
{ item.name }
-
-
-
-
-
-
-
SortOrder
-
{ item.sort_order }
-
-
-
-
-
-
-
WinProbability
-
{ item.win_probability }
-
-
-
-
-
-
-
IsWon
-
{ dataFormatter.booleanFormatter(item.is_won) }
-
-
-
-
-
-
-
IsLost
-
{ dataFormatter.booleanFormatter(item.is_lost) }
-
-
-
-
-
-
-
Active
-
{ dataFormatter.booleanFormatter(item.is_active) }
-
-
-
-
-
-
-
-
-
- ))}
- {!loading && pipeline_stages.length === 0 && (
-
- )}
-
-
- >
- )
-};
-
-export default ListPipeline_stages
\ No newline at end of file
diff --git a/frontend/src/components/Pipeline_stages/TablePipeline_stages.tsx b/frontend/src/components/Pipeline_stages/TablePipeline_stages.tsx
deleted file mode 100644
index 8c04ee0..0000000
--- a/frontend/src/components/Pipeline_stages/TablePipeline_stages.tsx
+++ /dev/null
@@ -1,476 +0,0 @@
-import React, { useEffect, useState, useMemo } from 'react'
-import { createPortal } from 'react-dom';
-import { ToastContainer, toast } from 'react-toastify';
-import BaseButton from '../BaseButton'
-import CardBoxModal from '../CardBoxModal'
-import CardBox from "../CardBox";
-import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/pipeline_stages/pipeline_stagesSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import { Field, Form, Formik } from "formik";
-import {
- DataGrid,
- GridColDef,
-} from '@mui/x-data-grid';
-import {loadColumns} from "./configurePipeline_stagesCols";
-import _ from 'lodash';
-import dataFormatter from '../../helpers/dataFormatter'
-import {dataGridStyles} from "../../styles";
-
-
-import ListPipeline_stages from './ListPipeline_stages';
-
-
-const perPage = 10
-
-const TableSamplePipeline_stages = ({ filterItems, setFilterItems, filters, showGrid }) => {
- const notify = (type, msg) => toast( msg, {type, position: "bottom-center"});
-
- const dispatch = useAppDispatch();
- const router = useRouter();
-
- const pagesList = [];
- const [id, setId] = useState(null);
- const [currentPage, setCurrentPage] = useState(0);
- const [filterRequest, setFilterRequest] = React.useState('');
- const [columns, setColumns] = useState([]);
- const [selectedRows, setSelectedRows] = useState([]);
- const [sortModel, setSortModel] = useState([
- {
- field: '',
- sort: 'desc',
- },
- ]);
-
- const { pipeline_stages, loading, count, notify: pipeline_stagesNotify, refetch } = useAppSelector((state) => state.pipeline_stages)
- const { currentUser } = useAppSelector((state) => state.auth);
- const focusRing = useAppSelector((state) => state.style.focusRingColor);
- const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
- const corners = useAppSelector((state) => state.style.corners);
- const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
- for (let i = 0; i < numPages; i++) {
- pagesList.push(i);
- }
-
- const loadData = async (page = currentPage, request = filterRequest) => {
- if (page !== currentPage) setCurrentPage(page);
- if (request !== filterRequest) setFilterRequest(request);
- const { sort, field } = sortModel[0];
-
- const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`;
- dispatch(fetch({ limit: perPage, page, query }));
- };
-
- useEffect(() => {
- if (pipeline_stagesNotify.showNotification) {
- notify(pipeline_stagesNotify.typeNotification, pipeline_stagesNotify.textNotification);
- }
- }, [pipeline_stagesNotify.showNotification]);
-
- useEffect(() => {
- if (!currentUser) return;
- loadData();
- }, [sortModel, currentUser]);
-
- useEffect(() => {
- if (refetch) {
- loadData(0);
- dispatch(setRefetch(false));
- }
- }, [refetch, dispatch]);
-
- const [isModalInfoActive, setIsModalInfoActive] = useState(false)
- const [isModalTrashActive, setIsModalTrashActive] = useState(false)
-
- const handleModalAction = () => {
- setIsModalInfoActive(false)
- setIsModalTrashActive(false)
- }
-
-
-
-
-
- const handleDeleteModalAction = (id: string) => {
- setId(id)
- setIsModalTrashActive(true)
- }
- const handleDeleteAction = async () => {
- if (id) {
- await dispatch(deleteItem(id));
- await loadData(0);
- setIsModalTrashActive(false);
- }
- };
-
- const generateFilterRequests = useMemo(() => {
- let request = '&';
- filterItems.forEach((item) => {
- const isRangeFilter = filters.find(
- (filter) =>
- filter.title === item.fields.selectedField &&
- (filter.number || filter.date),
- );
-
- if (isRangeFilter) {
- const from = item.fields.filterValueFrom;
- const to = item.fields.filterValueTo;
- if (from) {
- request += `${item.fields.selectedField}Range=${from}&`;
- }
- if (to) {
- request += `${item.fields.selectedField}Range=${to}&`;
- }
- } else {
- const value = item.fields.filterValue;
- if (value) {
- request += `${item.fields.selectedField}=${value}&`;
- }
- }
- });
- return request;
- }, [filterItems, filters]);
-
- const deleteFilter = (value) => {
- const newItems = filterItems.filter((item) => item.id !== value);
-
- if (newItems.length) {
- setFilterItems(newItems);
- } else {
- loadData(0, '');
-
- setFilterItems(newItems);
- }
- };
-
- const handleSubmit = () => {
- loadData(0, generateFilterRequests);
-
- };
-
- const handleChange = (id) => (e) => {
- const value = e.target.value;
- const name = e.target.name;
-
- setFilterItems(
- filterItems.map((item) => {
- if (item.id !== id) return item;
- if (name === 'selectedField') return { id, fields: { [name]: value } };
-
- return { id, fields: { ...item.fields, [name]: value } }
- }),
- );
- };
-
- const handleReset = () => {
- setFilterItems([]);
- loadData(0, '');
-
- };
-
- const onPageChange = (page: number) => {
- loadData(page);
- setCurrentPage(page);
- };
-
-
- useEffect(() => {
- if (!currentUser) return;
-
- loadColumns(
- handleDeleteModalAction,
- `pipeline_stages`,
- currentUser,
- ).then((newCols) => setColumns(newCols));
- }, [currentUser]);
-
-
-
- const handleTableSubmit = async (id: string, data) => {
-
- if (!_.isEmpty(data)) {
- await dispatch(update({ id, data }))
- .unwrap()
- .then((res) => res)
- .catch((err) => {
- throw new Error(err);
- });
- }
- };
-
- const onDeleteRows = async (selectedRows) => {
- await dispatch(deleteItemsByIds(selectedRows));
- await loadData(0);
- };
-
- const controlClasses =
- 'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' +
- ` ${bgColor} ${focusRing} ${corners} ` +
- 'dark:bg-slate-800 border';
-
-
- const dataGrid = (
-
- `datagrid--row`}
- rows={pipeline_stages ?? []}
- columns={columns}
- initialState={{
- pagination: {
- paginationModel: {
- pageSize: 10,
- },
- },
- }}
- disableRowSelectionOnClick
- onProcessRowUpdateError={(params) => {
- console.log('Error', params);
- }}
- processRowUpdate={async (newRow, oldRow) => {
- const data = dataFormatter.dataGridEditFormatter(newRow);
-
- try {
- await handleTableSubmit(newRow.id, data);
- return newRow;
- } catch {
- return oldRow;
- }
- }}
- sortingMode={'server'}
- checkboxSelection
- onRowSelectionModelChange={(ids) => {
- setSelectedRows(ids)
- }}
- onSortModelChange={(params) => {
- params.length
- ? setSortModel(params)
- : setSortModel([{ field: '', sort: 'desc' }]);
- }}
- rowCount={count}
- pageSizeOptions={[10]}
- paginationMode={'server'}
- loading={loading}
- onPaginationModelChange={(params) => {
- onPageChange(params.page);
- }}
- />
-
- )
-
- return (
- <>
- {filterItems && Array.isArray( filterItems ) && filterItems.length ?
-
- null}
- >
-
-
- : null
- }
-
- Are you sure you want to delete this item?
-
-
-
- {pipeline_stages && Array.isArray(pipeline_stages) && !showGrid && (
-
- )}
-
-
-
- {showGrid && dataGrid}
-
-
- {selectedRows.length > 0 &&
- createPortal(
- onDeleteRows(selectedRows)}
- />,
- document.getElementById('delete-rows-button'),
- )}
-
- >
- )
-}
-
-export default TableSamplePipeline_stages
diff --git a/frontend/src/components/Pipeline_stages/configurePipeline_stagesCols.tsx b/frontend/src/components/Pipeline_stages/configurePipeline_stagesCols.tsx
deleted file mode 100644
index ec9bd69..0000000
--- a/frontend/src/components/Pipeline_stages/configurePipeline_stagesCols.tsx
+++ /dev/null
@@ -1,163 +0,0 @@
-import React from 'react';
-import BaseIcon from '../BaseIcon';
-import { mdiEye, mdiTrashCan, mdiPencilOutline } from '@mdi/js';
-import axios from 'axios';
-import {
- GridActionsCellItem,
- GridRowParams,
- GridValueGetterParams,
-} from '@mui/x-data-grid';
-import ImageField from '../ImageField';
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter'
-import DataGridMultiSelect from "../DataGridMultiSelect";
-import ListActionsPopover from '../ListActionsPopover';
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-type Params = (id: string) => void;
-
-export const loadColumns = async (
- onDelete: Params,
- entityName: string,
-
- user
-
-) => {
- async function callOptionsApi(entityName: string) {
-
- if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
-
- try {
- const data = await axios(`/${entityName}/autocomplete?limit=100`);
- return data.data;
- } catch (error) {
- console.log(error);
- return [];
- }
- }
-
- const hasUpdatePermission = hasPermission(user, 'UPDATE_PIPELINE_STAGES')
-
- return [
-
- {
- field: 'name',
- headerName: 'StageName',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
-
- },
-
- {
- field: 'sort_order',
- headerName: 'SortOrder',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'number',
-
- },
-
- {
- field: 'win_probability',
- headerName: 'WinProbability',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'number',
-
- },
-
- {
- field: 'is_won',
- headerName: 'IsWon',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'boolean',
-
- },
-
- {
- field: 'is_lost',
- headerName: 'IsLost',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'boolean',
-
- },
-
- {
- field: 'is_active',
- headerName: 'Active',
- flex: 1,
- minWidth: 120,
- filterable: false,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
-
-
- editable: hasUpdatePermission,
-
- type: 'boolean',
-
- },
-
- {
- field: 'actions',
- type: 'actions',
- minWidth: 30,
- headerClassName: 'datagrid--header',
- cellClassName: 'datagrid--cell',
- getActions: (params: GridRowParams) => {
-
- return [
-
-
-
,
- ]
- },
- },
- ];
-};
diff --git a/frontend/src/helpers/dataFormatter.js b/frontend/src/helpers/dataFormatter.js
index 4504fd3..b6baeb7 100644
--- a/frontend/src/helpers/dataFormatter.js
+++ b/frontend/src/helpers/dataFormatter.js
@@ -100,134 +100,4 @@ export default {
if (!val) return ''
return {label: val.name, id: val.id}
},
-
-
-
- accountsManyListFormatter(val) {
- if (!val || !val.length) return []
- return val.map((item) => item.name)
- },
- accountsOneListFormatter(val) {
- if (!val) return ''
- return val.name
- },
- accountsManyListFormatterEdit(val) {
- if (!val || !val.length) return []
- return val.map((item) => {
- return {id: item.id, label: item.name}
- });
- },
- accountsOneListFormatterEdit(val) {
- if (!val) return ''
- return {label: val.name, id: val.id}
- },
-
-
-
- contactsManyListFormatter(val) {
- if (!val || !val.length) return []
- return val.map((item) => item.full_name)
- },
- contactsOneListFormatter(val) {
- if (!val) return ''
- return val.full_name
- },
- contactsManyListFormatterEdit(val) {
- if (!val || !val.length) return []
- return val.map((item) => {
- return {id: item.id, label: item.full_name}
- });
- },
- contactsOneListFormatterEdit(val) {
- if (!val) return ''
- return {label: val.full_name, id: val.id}
- },
-
-
-
- lead_sourcesManyListFormatter(val) {
- if (!val || !val.length) return []
- return val.map((item) => item.name)
- },
- lead_sourcesOneListFormatter(val) {
- if (!val) return ''
- return val.name
- },
- lead_sourcesManyListFormatterEdit(val) {
- if (!val || !val.length) return []
- return val.map((item) => {
- return {id: item.id, label: item.name}
- });
- },
- lead_sourcesOneListFormatterEdit(val) {
- if (!val) return ''
- return {label: val.name, id: val.id}
- },
-
-
-
- leadsManyListFormatter(val) {
- if (!val || !val.length) return []
- return val.map((item) => item.lead_name)
- },
- leadsOneListFormatter(val) {
- if (!val) return ''
- return val.lead_name
- },
- leadsManyListFormatterEdit(val) {
- if (!val || !val.length) return []
- return val.map((item) => {
- return {id: item.id, label: item.lead_name}
- });
- },
- leadsOneListFormatterEdit(val) {
- if (!val) return ''
- return {label: val.lead_name, id: val.id}
- },
-
-
-
- pipeline_stagesManyListFormatter(val) {
- if (!val || !val.length) return []
- return val.map((item) => item.name)
- },
- pipeline_stagesOneListFormatter(val) {
- if (!val) return ''
- return val.name
- },
- pipeline_stagesManyListFormatterEdit(val) {
- if (!val || !val.length) return []
- return val.map((item) => {
- return {id: item.id, label: item.name}
- });
- },
- pipeline_stagesOneListFormatterEdit(val) {
- if (!val) return ''
- return {label: val.name, id: val.id}
- },
-
-
-
- dealsManyListFormatter(val) {
- if (!val || !val.length) return []
- return val.map((item) => item.name)
- },
- dealsOneListFormatter(val) {
- if (!val) return ''
- return val.name
- },
- dealsManyListFormatterEdit(val) {
- if (!val || !val.length) return []
- return val.map((item) => {
- return {id: item.id, label: item.name}
- });
- },
- dealsOneListFormatterEdit(val) {
- if (!val) return ''
- return {label: val.name, id: val.id}
- },
-
-
-
-
}
diff --git a/frontend/src/pages/accounts/[accountsId].tsx b/frontend/src/pages/accounts/[accountsId].tsx
deleted file mode 100644
index 4c68924..0000000
--- a/frontend/src/pages/accounts/[accountsId].tsx
+++ /dev/null
@@ -1,1007 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/accounts/accountsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditAccounts = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'domain': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'industry': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- employee_count: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'annual_revenue': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'phone': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'website': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- address: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account_status: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_contacted_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- notes: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { accounts } = useAppSelector((state) => state.accounts)
-
-
- const { accountsId } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: accountsId }))
- }, [accountsId])
-
- useEffect(() => {
- if (typeof accounts === 'object') {
- setInitialValues(accounts)
- }
- }, [accounts])
-
- useEffect(() => {
- if (typeof accounts === 'object') {
-
- const newInitialVal = {...initVals};
-
- Object.keys(initVals).forEach(el => newInitialVal[el] = (accounts)[el])
-
- setInitialValues(newInitialVal);
- }
- }, [accounts])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: accountsId, data }))
- await router.push('/accounts/accounts-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit accounts')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditAccounts.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditAccounts
diff --git a/frontend/src/pages/accounts/accounts-edit.tsx b/frontend/src/pages/accounts/accounts-edit.tsx
deleted file mode 100644
index 2cb1d2f..0000000
--- a/frontend/src/pages/accounts/accounts-edit.tsx
+++ /dev/null
@@ -1,1004 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/accounts/accountsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditAccountsPage = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'domain': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'industry': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- employee_count: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'annual_revenue': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'phone': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'website': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- address: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account_status: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_contacted_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- notes: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { accounts } = useAppSelector((state) => state.accounts)
-
-
- const { id } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: id }))
- }, [id])
-
- useEffect(() => {
- if (typeof accounts === 'object') {
- setInitialValues(accounts)
- }
- }, [accounts])
-
- useEffect(() => {
- if (typeof accounts === 'object') {
- const newInitialVal = {...initVals};
- Object.keys(initVals).forEach(el => newInitialVal[el] = (accounts)[el])
- setInitialValues(newInitialVal);
- }
- }, [accounts])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: id, data }))
- await router.push('/accounts/accounts-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit accounts')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditAccountsPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditAccountsPage
diff --git a/frontend/src/pages/accounts/accounts-list.tsx b/frontend/src/pages/accounts/accounts-list.tsx
deleted file mode 100644
index 46592a7..0000000
--- a/frontend/src/pages/accounts/accounts-list.tsx
+++ /dev/null
@@ -1,170 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableAccounts from '../../components/Accounts/TableAccounts'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/accounts/accountsSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const AccountsTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'AccountName', title: 'name'},{label: 'Domain', title: 'domain'},{label: 'Industry', title: 'industry'},{label: 'Phone', title: 'phone'},{label: 'Website', title: 'website'},{label: 'Address', title: 'address'},{label: 'Notes', title: 'notes'},
- {label: 'EmployeeCount', title: 'employee_count', number: 'true'},
- {label: 'AnnualRevenue', title: 'annual_revenue', number: 'true'},
- {label: 'LastContactedAt', title: 'last_contacted_at', date: 'true'},{label: 'NextFollow-upAt', title: 'next_follow_up_at', date: 'true'},
-
-
- {label: 'Owner', title: 'owner'},
-
-
-
- {label: 'AccountStatus', title: 'account_status', type: 'enum', options: ['prospect','active_customer','former_customer','partner']},
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_ACCOUNTS');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getAccountsCSV = async () => {
- const response = await axios({url: '/accounts?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'accountsCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Accounts')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
- Switch to Table
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-AccountsTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default AccountsTablesPage
diff --git a/frontend/src/pages/accounts/accounts-new.tsx b/frontend/src/pages/accounts/accounts-new.tsx
deleted file mode 100644
index bf33cc1..0000000
--- a/frontend/src/pages/accounts/accounts-new.tsx
+++ /dev/null
@@ -1,754 +0,0 @@
-import { mdiAccount, mdiChartTimelineVariant, mdiMail, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SwitchField } from '../../components/SwitchField'
-
-import { SelectField } from '../../components/SelectField'
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import {RichTextField} from "../../components/RichTextField";
-
-import { create } from '../../stores/accounts/accountsSlice'
-import { useAppDispatch } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import moment from 'moment';
-
-const initialValues = {
-
-
- name: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- domain: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- industry: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- employee_count: '',
-
-
-
-
-
-
-
-
-
-
-
-
- annual_revenue: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- phone: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- website: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- address: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
- account_status: 'prospect',
-
-
-
-
-
-
-
-
-
-
-
-
- last_contacted_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
- notes: '',
-
-
-
-
-
-
-
-
-
-
-
-
-}
-
-
-const AccountsNew = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
-
-
-
-
- const handleSubmit = async (data) => {
- await dispatch(create(data))
- await router.push('/accounts/accounts-list')
- }
- return (
- <>
-
- {getPageTitle('New Item')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-AccountsNew.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default AccountsNew
diff --git a/frontend/src/pages/accounts/accounts-table.tsx b/frontend/src/pages/accounts/accounts-table.tsx
deleted file mode 100644
index b78e670..0000000
--- a/frontend/src/pages/accounts/accounts-table.tsx
+++ /dev/null
@@ -1,168 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableAccounts from '../../components/Accounts/TableAccounts'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/accounts/accountsSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const AccountsTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'AccountName', title: 'name'},{label: 'Domain', title: 'domain'},{label: 'Industry', title: 'industry'},{label: 'Phone', title: 'phone'},{label: 'Website', title: 'website'},{label: 'Address', title: 'address'},{label: 'Notes', title: 'notes'},
- {label: 'EmployeeCount', title: 'employee_count', number: 'true'},
- {label: 'AnnualRevenue', title: 'annual_revenue', number: 'true'},
- {label: 'LastContactedAt', title: 'last_contacted_at', date: 'true'},{label: 'NextFollow-upAt', title: 'next_follow_up_at', date: 'true'},
-
-
- {label: 'Owner', title: 'owner'},
-
-
-
- {label: 'AccountStatus', title: 'account_status', type: 'enum', options: ['prospect','active_customer','former_customer','partner']},
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_ACCOUNTS');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getAccountsCSV = async () => {
- const response = await axios({url: '/accounts?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'accountsCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Accounts')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
-
- Back to
card
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-AccountsTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default AccountsTablesPage
diff --git a/frontend/src/pages/accounts/accounts-view.tsx b/frontend/src/pages/accounts/accounts-view.tsx
deleted file mode 100644
index e853732..0000000
--- a/frontend/src/pages/accounts/accounts-view.tsx
+++ /dev/null
@@ -1,1065 +0,0 @@
-import React, { ReactElement, useEffect } from 'react';
-import Head from 'next/head'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import {useRouter} from "next/router";
-import { fetch } from '../../stores/accounts/accountsSlice'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-import LayoutAuthenticated from "../../layouts/Authenticated";
-import {getPageTitle} from "../../config";
-import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton";
-import SectionMain from "../../components/SectionMain";
-import CardBox from "../../components/CardBox";
-import BaseButton from "../../components/BaseButton";
-import BaseDivider from "../../components/BaseDivider";
-import {mdiChartTimelineVariant} from "@mdi/js";
-import {SwitchField} from "../../components/SwitchField";
-import FormField from "../../components/FormField";
-
-
-const AccountsView = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const { accounts } = useAppSelector((state) => state.accounts)
-
-
- const { id } = router.query;
-
- function removeLastCharacter(str) {
- console.log(str,`str`)
- return str.slice(0, -1);
- }
-
- useEffect(() => {
- dispatch(fetch({ id }));
- }, [dispatch, id]);
-
-
- return (
- <>
-
- {getPageTitle('View accounts')}
-
-
-
-
-
-
-
-
-
-
-
AccountName
-
{accounts?.name}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Domain
-
{accounts?.domain}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Industry
-
{accounts?.industry}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
EmployeeCount
-
{accounts?.employee_count || 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
AnnualRevenue
-
{accounts?.annual_revenue || 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Phone
-
{accounts?.phone}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Website
-
{accounts?.website}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Owner
-
-
-
{accounts?.owner?.firstName ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
AccountStatus
-
{accounts?.account_status ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {accounts.last_contacted_at ? : No LastContactedAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {accounts.next_follow_up_at ? : No NextFollow-upAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Notes
- {accounts.notes
- ?
- :
No data
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <>
- Contacts Account
-
-
-
-
-
-
-
- | FullName |
-
-
-
- Email |
-
-
-
- Phone |
-
-
-
- JobTitle |
-
-
-
-
-
-
-
- ContactStatus |
-
-
-
- LinkedInURL |
-
-
-
-
-
- LastContactedAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
- {accounts.contacts_account && Array.isArray(accounts.contacts_account) &&
- accounts.contacts_account.map((item: any) => (
- router.push(`/contacts/contacts-view/?id=${item.id}`)}>
-
-
- |
- { item.full_name }
- |
-
-
-
-
- { item.email }
- |
-
-
-
-
- { item.phone }
- |
-
-
-
-
- { item.job_title }
- |
-
-
-
-
-
-
-
-
- { item.contact_status }
- |
-
-
-
-
- { item.linkedin_url }
- |
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_contacted_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
- ))}
-
-
-
- {!accounts?.contacts_account?.length && No data
}
-
- >
-
-
-
- <>
- Leads LinkedAccount
-
-
-
-
-
-
-
- | LeadName |
-
-
-
- CompanyName |
-
-
-
- Email |
-
-
-
- Phone |
-
-
-
-
-
-
-
- LeadStatus |
-
-
-
- LeadRating |
-
-
-
-
-
- LastContactedAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
-
-
-
-
- {accounts.leads_account && Array.isArray(accounts.leads_account) &&
- accounts.leads_account.map((item: any) => (
- router.push(`/leads/leads-view/?id=${item.id}`)}>
-
-
- |
- { item.lead_name }
- |
-
-
-
-
- { item.company_name }
- |
-
-
-
-
- { item.email }
- |
-
-
-
-
- { item.phone }
- |
-
-
-
-
-
-
-
-
- { item.lead_status }
- |
-
-
-
-
- { item.lead_rating }
- |
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_contacted_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
-
-
-
-
- ))}
-
-
-
- {!accounts?.leads_account?.length && No data
}
-
- >
-
-
-
- <>
- Deals Account
-
-
-
-
-
-
-
- | DealName |
-
-
-
-
-
-
-
-
-
-
-
-
-
- Amount |
-
-
-
- Currency |
-
-
-
- ExpectedCloseDate |
-
-
-
- ClosedDate |
-
-
-
- DealStatus |
-
-
-
- LossReason |
-
-
-
- LastActivityAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
-
-
- {accounts.deals_account && Array.isArray(accounts.deals_account) &&
- accounts.deals_account.map((item: any) => (
- router.push(`/deals/deals-view/?id=${item.id}`)}>
-
-
- |
- { item.name }
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { item.amount }
- |
-
-
-
-
- { item.currency }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.expected_close_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.closed_at) }
- |
-
-
-
-
- { item.deal_status }
- |
-
-
-
-
- { item.loss_reason }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_activity_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
-
-
- ))}
-
-
-
- {!accounts?.deals_account?.length && No data
}
-
- >
-
-
- <>
- Activities Account
-
-
-
-
-
-
-
- | ActivityType |
-
-
-
- Subject |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ActivityAt |
-
-
-
- DueAt |
-
-
-
- CompletedAt |
-
-
-
- Status |
-
-
-
- Priority |
-
-
-
-
-
-
-
- {accounts.activities_account && Array.isArray(accounts.activities_account) &&
- accounts.activities_account.map((item: any) => (
- router.push(`/activities/activities-view/?id=${item.id}`)}>
-
-
- |
- { item.activity_type }
- |
-
-
-
-
- { item.subject }
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.activity_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.due_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.completed_at) }
- |
-
-
-
-
- { item.status }
- |
-
-
-
-
- { item.priority }
- |
-
-
-
-
-
- ))}
-
-
-
- {!accounts?.activities_account?.length && No data
}
-
- >
-
-
-
-
-
- router.push('/accounts/accounts-list')}
- />
-
-
- >
- );
-};
-
-AccountsView.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default AccountsView;
\ No newline at end of file
diff --git a/frontend/src/pages/activities/[activitiesId].tsx b/frontend/src/pages/activities/[activitiesId].tsx
deleted file mode 100644
index ced8388..0000000
--- a/frontend/src/pages/activities/[activitiesId].tsx
+++ /dev/null
@@ -1,1204 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/activities/activitiesSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditActivities = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- activity_type: '',
-
-
-
-
-
-
-
-
-
-
-
- 'subject': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- details: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- lead: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- deal: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- contact: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- activity_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- due_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- completed_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- status: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- priority: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- attachments: [],
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { activities } = useAppSelector((state) => state.activities)
-
-
- const { activitiesId } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: activitiesId }))
- }, [activitiesId])
-
- useEffect(() => {
- if (typeof activities === 'object') {
- setInitialValues(activities)
- }
- }, [activities])
-
- useEffect(() => {
- if (typeof activities === 'object') {
-
- const newInitialVal = {...initVals};
-
- Object.keys(initVals).forEach(el => newInitialVal[el] = (activities)[el])
-
- setInitialValues(newInitialVal);
- }
- }, [activities])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: activitiesId, data }))
- await router.push('/activities/activities-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit activities')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditActivities.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditActivities
diff --git a/frontend/src/pages/activities/activities-edit.tsx b/frontend/src/pages/activities/activities-edit.tsx
deleted file mode 100644
index cfd57fb..0000000
--- a/frontend/src/pages/activities/activities-edit.tsx
+++ /dev/null
@@ -1,1201 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/activities/activitiesSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditActivitiesPage = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- activity_type: '',
-
-
-
-
-
-
-
-
-
-
-
- 'subject': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- details: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- lead: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- deal: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- contact: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- activity_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- due_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- completed_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- status: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- priority: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- attachments: [],
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { activities } = useAppSelector((state) => state.activities)
-
-
- const { id } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: id }))
- }, [id])
-
- useEffect(() => {
- if (typeof activities === 'object') {
- setInitialValues(activities)
- }
- }, [activities])
-
- useEffect(() => {
- if (typeof activities === 'object') {
- const newInitialVal = {...initVals};
- Object.keys(initVals).forEach(el => newInitialVal[el] = (activities)[el])
- setInitialValues(newInitialVal);
- }
- }, [activities])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: id, data }))
- await router.push('/activities/activities-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit activities')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditActivitiesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditActivitiesPage
diff --git a/frontend/src/pages/activities/activities-list.tsx b/frontend/src/pages/activities/activities-list.tsx
deleted file mode 100644
index b08f4f3..0000000
--- a/frontend/src/pages/activities/activities-list.tsx
+++ /dev/null
@@ -1,186 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableActivities from '../../components/Activities/TableActivities'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/activities/activitiesSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const ActivitiesTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'Subject', title: 'subject'},{label: 'Details', title: 'details'},
-
-
- {label: 'ActivityAt', title: 'activity_at', date: 'true'},{label: 'DueAt', title: 'due_at', date: 'true'},{label: 'CompletedAt', title: 'completed_at', date: 'true'},
-
-
- {label: 'Owner', title: 'owner'},
-
-
-
- {label: 'Lead', title: 'lead'},
-
-
-
- {label: 'Deal', title: 'deal'},
-
-
-
- {label: 'Contact', title: 'contact'},
-
-
-
- {label: 'Account', title: 'account'},
-
-
-
- {label: 'ActivityType', title: 'activity_type', type: 'enum', options: ['call','email','meeting','task','note']},{label: 'Status', title: 'status', type: 'enum', options: ['planned','completed','canceled']},{label: 'Priority', title: 'priority', type: 'enum', options: ['low','medium','high']},
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_ACTIVITIES');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getActivitiesCSV = async () => {
- const response = await axios({url: '/activities?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'activitiesCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Activities')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
- Switch to Table
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-ActivitiesTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default ActivitiesTablesPage
diff --git a/frontend/src/pages/activities/activities-new.tsx b/frontend/src/pages/activities/activities-new.tsx
deleted file mode 100644
index 824bac2..0000000
--- a/frontend/src/pages/activities/activities-new.tsx
+++ /dev/null
@@ -1,816 +0,0 @@
-import { mdiAccount, mdiChartTimelineVariant, mdiMail, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SwitchField } from '../../components/SwitchField'
-
-import { SelectField } from '../../components/SelectField'
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import {RichTextField} from "../../components/RichTextField";
-
-import { create } from '../../stores/activities/activitiesSlice'
-import { useAppDispatch } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import moment from 'moment';
-
-const initialValues = {
-
-
-
-
-
-
-
-
-
-
-
- activity_type: 'call',
-
-
-
-
-
-
-
- subject: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- details: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- lead: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- deal: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- contact: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: '',
-
-
-
-
-
-
-
-
-
- activity_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- due_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- completed_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- status: 'planned',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- priority: 'low',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- attachments: [],
-
-
-
-
-
-}
-
-
-const ActivitiesNew = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
-
-
-
- // get from url params
- const { dateRangeStart, dateRangeEnd } = router.query
-
-
- const handleSubmit = async (data) => {
- await dispatch(create(data))
- await router.push('/activities/activities-list')
- }
- return (
- <>
-
- {getPageTitle('New Item')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-ActivitiesNew.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default ActivitiesNew
diff --git a/frontend/src/pages/activities/activities-table.tsx b/frontend/src/pages/activities/activities-table.tsx
deleted file mode 100644
index 46aa44c..0000000
--- a/frontend/src/pages/activities/activities-table.tsx
+++ /dev/null
@@ -1,184 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableActivities from '../../components/Activities/TableActivities'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/activities/activitiesSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const ActivitiesTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'Subject', title: 'subject'},{label: 'Details', title: 'details'},
-
-
- {label: 'ActivityAt', title: 'activity_at', date: 'true'},{label: 'DueAt', title: 'due_at', date: 'true'},{label: 'CompletedAt', title: 'completed_at', date: 'true'},
-
-
- {label: 'Owner', title: 'owner'},
-
-
-
- {label: 'Lead', title: 'lead'},
-
-
-
- {label: 'Deal', title: 'deal'},
-
-
-
- {label: 'Contact', title: 'contact'},
-
-
-
- {label: 'Account', title: 'account'},
-
-
-
- {label: 'ActivityType', title: 'activity_type', type: 'enum', options: ['call','email','meeting','task','note']},{label: 'Status', title: 'status', type: 'enum', options: ['planned','completed','canceled']},{label: 'Priority', title: 'priority', type: 'enum', options: ['low','medium','high']},
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_ACTIVITIES');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getActivitiesCSV = async () => {
- const response = await axios({url: '/activities?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'activitiesCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Activities')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
-
- Back to
calendar
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-ActivitiesTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default ActivitiesTablesPage
diff --git a/frontend/src/pages/activities/activities-view.tsx b/frontend/src/pages/activities/activities-view.tsx
deleted file mode 100644
index 2b31022..0000000
--- a/frontend/src/pages/activities/activities-view.tsx
+++ /dev/null
@@ -1,699 +0,0 @@
-import React, { ReactElement, useEffect } from 'react';
-import Head from 'next/head'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import {useRouter} from "next/router";
-import { fetch } from '../../stores/activities/activitiesSlice'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-import LayoutAuthenticated from "../../layouts/Authenticated";
-import {getPageTitle} from "../../config";
-import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton";
-import SectionMain from "../../components/SectionMain";
-import CardBox from "../../components/CardBox";
-import BaseButton from "../../components/BaseButton";
-import BaseDivider from "../../components/BaseDivider";
-import {mdiChartTimelineVariant} from "@mdi/js";
-import {SwitchField} from "../../components/SwitchField";
-import FormField from "../../components/FormField";
-
-
-const ActivitiesView = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const { activities } = useAppSelector((state) => state.activities)
-
-
- const { id } = router.query;
-
- function removeLastCharacter(str) {
- console.log(str,`str`)
- return str.slice(0, -1);
- }
-
- useEffect(() => {
- dispatch(fetch({ id }));
- }, [dispatch, id]);
-
-
- return (
- <>
-
- {getPageTitle('View activities')}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
ActivityType
-
{activities?.activity_type ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Subject
-
{activities?.subject}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Details
- {activities.details
- ?
- :
No data
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Owner
-
-
-
{activities?.owner?.firstName ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Lead
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{activities?.lead?.lead_name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Deal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{activities?.deal?.name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Contact
-
-
-
-
-
-
-
-
-
-
-
{activities?.contact?.full_name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Account
-
-
-
-
-
-
-
-
-
{activities?.account?.name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {activities.activity_at ? : No ActivityAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {activities.due_at ? : No DueAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {activities.completed_at ? : No CompletedAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Status
-
{activities?.status ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Priority
-
{activities?.priority ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Attachments
- {activities?.attachments?.length
- ? dataFormatter.filesFormatter(activities.attachments).map(link => (
-
- )) :
No Attachments
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- router.push('/activities/activities-list')}
- />
-
-
- >
- );
-};
-
-ActivitiesView.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default ActivitiesView;
\ No newline at end of file
diff --git a/frontend/src/pages/contacts/[contactsId].tsx b/frontend/src/pages/contacts/[contactsId].tsx
deleted file mode 100644
index 7d7a312..0000000
--- a/frontend/src/pages/contacts/[contactsId].tsx
+++ /dev/null
@@ -1,907 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/contacts/contactsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditContacts = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'full_name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'email': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'phone': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'job_title': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- contact_status: '',
-
-
-
-
-
-
-
-
-
-
-
- 'linkedin_url': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- notes: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_contacted_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { contacts } = useAppSelector((state) => state.contacts)
-
-
- const { contactsId } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: contactsId }))
- }, [contactsId])
-
- useEffect(() => {
- if (typeof contacts === 'object') {
- setInitialValues(contacts)
- }
- }, [contacts])
-
- useEffect(() => {
- if (typeof contacts === 'object') {
-
- const newInitialVal = {...initVals};
-
- Object.keys(initVals).forEach(el => newInitialVal[el] = (contacts)[el])
-
- setInitialValues(newInitialVal);
- }
- }, [contacts])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: contactsId, data }))
- await router.push('/contacts/contacts-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit contacts')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditContacts.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditContacts
diff --git a/frontend/src/pages/contacts/contacts-edit.tsx b/frontend/src/pages/contacts/contacts-edit.tsx
deleted file mode 100644
index 02a2332..0000000
--- a/frontend/src/pages/contacts/contacts-edit.tsx
+++ /dev/null
@@ -1,904 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/contacts/contactsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditContactsPage = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'full_name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'email': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'phone': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'job_title': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- contact_status: '',
-
-
-
-
-
-
-
-
-
-
-
- 'linkedin_url': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- notes: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_contacted_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { contacts } = useAppSelector((state) => state.contacts)
-
-
- const { id } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: id }))
- }, [id])
-
- useEffect(() => {
- if (typeof contacts === 'object') {
- setInitialValues(contacts)
- }
- }, [contacts])
-
- useEffect(() => {
- if (typeof contacts === 'object') {
- const newInitialVal = {...initVals};
- Object.keys(initVals).forEach(el => newInitialVal[el] = (contacts)[el])
- setInitialValues(newInitialVal);
- }
- }, [contacts])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: id, data }))
- await router.push('/contacts/contacts-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit contacts')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditContactsPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditContactsPage
diff --git a/frontend/src/pages/contacts/contacts-list.tsx b/frontend/src/pages/contacts/contacts-list.tsx
deleted file mode 100644
index d82e2f3..0000000
--- a/frontend/src/pages/contacts/contacts-list.tsx
+++ /dev/null
@@ -1,170 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableContacts from '../../components/Contacts/TableContacts'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/contacts/contactsSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const ContactsTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'FullName', title: 'full_name'},{label: 'Email', title: 'email'},{label: 'Phone', title: 'phone'},{label: 'JobTitle', title: 'job_title'},{label: 'LinkedInURL', title: 'linkedin_url'},{label: 'Notes', title: 'notes'},
-
-
- {label: 'LastContactedAt', title: 'last_contacted_at', date: 'true'},{label: 'NextFollow-upAt', title: 'next_follow_up_at', date: 'true'},
-
-
- {label: 'Account', title: 'account'},
-
-
-
- {label: 'Owner', title: 'owner'},
-
-
-
- {label: 'ContactStatus', title: 'contact_status', type: 'enum', options: ['active','do_not_contact','bounced','unsubscribed']},
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_CONTACTS');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getContactsCSV = async () => {
- const response = await axios({url: '/contacts?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'contactsCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Contacts')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-ContactsTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default ContactsTablesPage
diff --git a/frontend/src/pages/contacts/contacts-new.tsx b/frontend/src/pages/contacts/contacts-new.tsx
deleted file mode 100644
index 2e08e20..0000000
--- a/frontend/src/pages/contacts/contacts-new.tsx
+++ /dev/null
@@ -1,650 +0,0 @@
-import { mdiAccount, mdiChartTimelineVariant, mdiMail, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SwitchField } from '../../components/SwitchField'
-
-import { SelectField } from '../../components/SelectField'
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import {RichTextField} from "../../components/RichTextField";
-
-import { create } from '../../stores/contacts/contactsSlice'
-import { useAppDispatch } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import moment from 'moment';
-
-const initialValues = {
-
-
- full_name: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- email: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- phone: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- job_title: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
- contact_status: 'active',
-
-
-
-
-
-
-
- linkedin_url: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- notes: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_contacted_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: '',
-
-
-
-
-
-
-
-
-
-}
-
-
-const ContactsNew = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
-
-
-
-
- const handleSubmit = async (data) => {
- await dispatch(create(data))
- await router.push('/contacts/contacts-list')
- }
- return (
- <>
-
- {getPageTitle('New Item')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-ContactsNew.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default ContactsNew
diff --git a/frontend/src/pages/contacts/contacts-table.tsx b/frontend/src/pages/contacts/contacts-table.tsx
deleted file mode 100644
index cc79c3a..0000000
--- a/frontend/src/pages/contacts/contacts-table.tsx
+++ /dev/null
@@ -1,172 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableContacts from '../../components/Contacts/TableContacts'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/contacts/contactsSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const ContactsTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'FullName', title: 'full_name'},{label: 'Email', title: 'email'},{label: 'Phone', title: 'phone'},{label: 'JobTitle', title: 'job_title'},{label: 'LinkedInURL', title: 'linkedin_url'},{label: 'Notes', title: 'notes'},
-
-
- {label: 'LastContactedAt', title: 'last_contacted_at', date: 'true'},{label: 'NextFollow-upAt', title: 'next_follow_up_at', date: 'true'},
-
-
- {label: 'Account', title: 'account'},
-
-
-
- {label: 'Owner', title: 'owner'},
-
-
-
- {label: 'ContactStatus', title: 'contact_status', type: 'enum', options: ['active','do_not_contact','bounced','unsubscribed']},
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_CONTACTS');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getContactsCSV = async () => {
- const response = await axios({url: '/contacts?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'contactsCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Contacts')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
-
- Back to
table
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-ContactsTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default ContactsTablesPage
diff --git a/frontend/src/pages/contacts/contacts-view.tsx b/frontend/src/pages/contacts/contacts-view.tsx
deleted file mode 100644
index 4099a68..0000000
--- a/frontend/src/pages/contacts/contacts-view.tsx
+++ /dev/null
@@ -1,907 +0,0 @@
-import React, { ReactElement, useEffect } from 'react';
-import Head from 'next/head'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import {useRouter} from "next/router";
-import { fetch } from '../../stores/contacts/contactsSlice'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-import LayoutAuthenticated from "../../layouts/Authenticated";
-import {getPageTitle} from "../../config";
-import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton";
-import SectionMain from "../../components/SectionMain";
-import CardBox from "../../components/CardBox";
-import BaseButton from "../../components/BaseButton";
-import BaseDivider from "../../components/BaseDivider";
-import {mdiChartTimelineVariant} from "@mdi/js";
-import {SwitchField} from "../../components/SwitchField";
-import FormField from "../../components/FormField";
-
-
-const ContactsView = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const { contacts } = useAppSelector((state) => state.contacts)
-
-
- const { id } = router.query;
-
- function removeLastCharacter(str) {
- console.log(str,`str`)
- return str.slice(0, -1);
- }
-
- useEffect(() => {
- dispatch(fetch({ id }));
- }, [dispatch, id]);
-
-
- return (
- <>
-
- {getPageTitle('View contacts')}
-
-
-
-
-
-
-
-
-
-
-
FullName
-
{contacts?.full_name}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Email
-
{contacts?.email}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Phone
-
{contacts?.phone}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
JobTitle
-
{contacts?.job_title}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Account
-
-
-
-
-
-
-
-
-
{contacts?.account?.name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Owner
-
-
-
{contacts?.owner?.firstName ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
ContactStatus
-
{contacts?.contact_status ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
LinkedInURL
-
{contacts?.linkedin_url}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Notes
- {contacts.notes
- ?
- :
No data
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {contacts.last_contacted_at ? : No LastContactedAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {contacts.next_follow_up_at ? : No NextFollow-upAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <>
- Leads PrimaryContact
-
-
-
-
-
-
-
- | LeadName |
-
-
-
- CompanyName |
-
-
-
- Email |
-
-
-
- Phone |
-
-
-
-
-
-
-
- LeadStatus |
-
-
-
- LeadRating |
-
-
-
-
-
- LastContactedAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
-
-
-
-
- {contacts.leads_primary_contact && Array.isArray(contacts.leads_primary_contact) &&
- contacts.leads_primary_contact.map((item: any) => (
- router.push(`/leads/leads-view/?id=${item.id}`)}>
-
-
- |
- { item.lead_name }
- |
-
-
-
-
- { item.company_name }
- |
-
-
-
-
- { item.email }
- |
-
-
-
-
- { item.phone }
- |
-
-
-
-
-
-
-
-
- { item.lead_status }
- |
-
-
-
-
- { item.lead_rating }
- |
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_contacted_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
-
-
-
-
- ))}
-
-
-
- {!contacts?.leads_primary_contact?.length && No data
}
-
- >
-
-
-
- <>
- Deals PrimaryContact
-
-
-
-
-
-
-
- | DealName |
-
-
-
-
-
-
-
-
-
-
-
-
-
- Amount |
-
-
-
- Currency |
-
-
-
- ExpectedCloseDate |
-
-
-
- ClosedDate |
-
-
-
- DealStatus |
-
-
-
- LossReason |
-
-
-
- LastActivityAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
-
-
- {contacts.deals_primary_contact && Array.isArray(contacts.deals_primary_contact) &&
- contacts.deals_primary_contact.map((item: any) => (
- router.push(`/deals/deals-view/?id=${item.id}`)}>
-
-
- |
- { item.name }
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { item.amount }
- |
-
-
-
-
- { item.currency }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.expected_close_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.closed_at) }
- |
-
-
-
-
- { item.deal_status }
- |
-
-
-
-
- { item.loss_reason }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_activity_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
-
-
- ))}
-
-
-
- {!contacts?.deals_primary_contact?.length && No data
}
-
- >
-
-
- <>
- Activities Contact
-
-
-
-
-
-
-
- | ActivityType |
-
-
-
- Subject |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ActivityAt |
-
-
-
- DueAt |
-
-
-
- CompletedAt |
-
-
-
- Status |
-
-
-
- Priority |
-
-
-
-
-
-
-
- {contacts.activities_contact && Array.isArray(contacts.activities_contact) &&
- contacts.activities_contact.map((item: any) => (
- router.push(`/activities/activities-view/?id=${item.id}`)}>
-
-
- |
- { item.activity_type }
- |
-
-
-
-
- { item.subject }
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.activity_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.due_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.completed_at) }
- |
-
-
-
-
- { item.status }
- |
-
-
-
-
- { item.priority }
- |
-
-
-
-
-
- ))}
-
-
-
- {!contacts?.activities_contact?.length && No data
}
-
- >
-
-
-
-
-
- router.push('/contacts/contacts-list')}
- />
-
-
- >
- );
-};
-
-ContactsView.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default ContactsView;
\ No newline at end of file
diff --git a/frontend/src/pages/deals/[dealsId].tsx b/frontend/src/pages/deals/[dealsId].tsx
deleted file mode 100644
index 923bd6f..0000000
--- a/frontend/src/pages/deals/[dealsId].tsx
+++ /dev/null
@@ -1,1254 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/deals/dealsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditDeals = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- stage: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- primary_contact: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- originating_lead: null,
-
-
-
-
-
- 'amount': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'currency': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- expected_close_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- closed_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- deal_status: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
- loss_reason: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_activity_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- description: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { deals } = useAppSelector((state) => state.deals)
-
-
- const { dealsId } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: dealsId }))
- }, [dealsId])
-
- useEffect(() => {
- if (typeof deals === 'object') {
- setInitialValues(deals)
- }
- }, [deals])
-
- useEffect(() => {
- if (typeof deals === 'object') {
-
- const newInitialVal = {...initVals};
-
- Object.keys(initVals).forEach(el => newInitialVal[el] = (deals)[el])
-
- setInitialValues(newInitialVal);
- }
- }, [deals])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: dealsId, data }))
- await router.push('/deals/deals-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit deals')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditDeals.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditDeals
diff --git a/frontend/src/pages/deals/deals-edit.tsx b/frontend/src/pages/deals/deals-edit.tsx
deleted file mode 100644
index f4f3219..0000000
--- a/frontend/src/pages/deals/deals-edit.tsx
+++ /dev/null
@@ -1,1251 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/deals/dealsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditDealsPage = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- stage: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- primary_contact: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- originating_lead: null,
-
-
-
-
-
- 'amount': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'currency': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- expected_close_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- closed_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- deal_status: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
- loss_reason: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_activity_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- description: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { deals } = useAppSelector((state) => state.deals)
-
-
- const { id } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: id }))
- }, [id])
-
- useEffect(() => {
- if (typeof deals === 'object') {
- setInitialValues(deals)
- }
- }, [deals])
-
- useEffect(() => {
- if (typeof deals === 'object') {
- const newInitialVal = {...initVals};
- Object.keys(initVals).forEach(el => newInitialVal[el] = (deals)[el])
- setInitialValues(newInitialVal);
- }
- }, [deals])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: id, data }))
- await router.push('/deals/deals-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit deals')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditDealsPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditDealsPage
diff --git a/frontend/src/pages/deals/deals-list.tsx b/frontend/src/pages/deals/deals-list.tsx
deleted file mode 100644
index 193ed75..0000000
--- a/frontend/src/pages/deals/deals-list.tsx
+++ /dev/null
@@ -1,184 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableDeals from '../../components/Deals/TableDeals'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/deals/dealsSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const DealsTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'DealName', title: 'name'},{label: 'Currency', title: 'currency'},{label: 'LossReason', title: 'loss_reason'},{label: 'Description', title: 'description'},
-
- {label: 'Amount', title: 'amount', number: 'true'},
- {label: 'ExpectedCloseDate', title: 'expected_close_at', date: 'true'},{label: 'ClosedDate', title: 'closed_at', date: 'true'},{label: 'LastActivityAt', title: 'last_activity_at', date: 'true'},{label: 'NextFollow-upAt', title: 'next_follow_up_at', date: 'true'},
-
-
- {label: 'Stage', title: 'stage'},
-
-
-
- {label: 'Owner', title: 'owner'},
-
-
-
- {label: 'Account', title: 'account'},
-
-
-
- {label: 'PrimaryContact', title: 'primary_contact'},
-
-
-
- {label: 'OriginatingLead', title: 'originating_lead'},
-
-
-
- {label: 'DealStatus', title: 'deal_status', type: 'enum', options: ['open','won','lost']},
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_DEALS');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getDealsCSV = async () => {
- const response = await axios({url: '/deals?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'dealsCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Deals')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
- Switch to Table
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-DealsTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default DealsTablesPage
diff --git a/frontend/src/pages/deals/deals-new.tsx b/frontend/src/pages/deals/deals-new.tsx
deleted file mode 100644
index 83b9f77..0000000
--- a/frontend/src/pages/deals/deals-new.tsx
+++ /dev/null
@@ -1,835 +0,0 @@
-import { mdiAccount, mdiChartTimelineVariant, mdiMail, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SwitchField } from '../../components/SwitchField'
-
-import { SelectField } from '../../components/SelectField'
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import {RichTextField} from "../../components/RichTextField";
-
-import { create } from '../../stores/deals/dealsSlice'
-import { useAppDispatch } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import moment from 'moment';
-
-const initialValues = {
-
-
- name: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- stage: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- primary_contact: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- originating_lead: '',
-
-
-
-
- amount: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- currency: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- expected_close_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- closed_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- deal_status: 'open',
-
-
-
-
-
-
-
-
- loss_reason: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_activity_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
- description: '',
-
-
-
-
-
-
-
-
-
-
-
-
-}
-
-
-const DealsNew = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
-
-
-
-
- const handleSubmit = async (data) => {
- await dispatch(create(data))
- await router.push('/deals/deals-list')
- }
- return (
- <>
-
- {getPageTitle('New Item')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-DealsNew.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default DealsNew
diff --git a/frontend/src/pages/deals/deals-table.tsx b/frontend/src/pages/deals/deals-table.tsx
deleted file mode 100644
index 0fb1b00..0000000
--- a/frontend/src/pages/deals/deals-table.tsx
+++ /dev/null
@@ -1,184 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableDeals from '../../components/Deals/TableDeals'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/deals/dealsSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const DealsTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'DealName', title: 'name'},{label: 'Currency', title: 'currency'},{label: 'LossReason', title: 'loss_reason'},{label: 'Description', title: 'description'},
-
- {label: 'Amount', title: 'amount', number: 'true'},
- {label: 'ExpectedCloseDate', title: 'expected_close_at', date: 'true'},{label: 'ClosedDate', title: 'closed_at', date: 'true'},{label: 'LastActivityAt', title: 'last_activity_at', date: 'true'},{label: 'NextFollow-upAt', title: 'next_follow_up_at', date: 'true'},
-
-
- {label: 'Stage', title: 'stage'},
-
-
-
- {label: 'Owner', title: 'owner'},
-
-
-
- {label: 'Account', title: 'account'},
-
-
-
- {label: 'PrimaryContact', title: 'primary_contact'},
-
-
-
- {label: 'OriginatingLead', title: 'originating_lead'},
-
-
-
- {label: 'DealStatus', title: 'deal_status', type: 'enum', options: ['open','won','lost']},
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_DEALS');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getDealsCSV = async () => {
- const response = await axios({url: '/deals?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'dealsCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Deals')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
-
- Back to
kanban
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-DealsTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default DealsTablesPage
diff --git a/frontend/src/pages/deals/deals-view.tsx b/frontend/src/pages/deals/deals-view.tsx
deleted file mode 100644
index 22c50fe..0000000
--- a/frontend/src/pages/deals/deals-view.tsx
+++ /dev/null
@@ -1,854 +0,0 @@
-import React, { ReactElement, useEffect } from 'react';
-import Head from 'next/head'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import {useRouter} from "next/router";
-import { fetch } from '../../stores/deals/dealsSlice'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-import LayoutAuthenticated from "../../layouts/Authenticated";
-import {getPageTitle} from "../../config";
-import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton";
-import SectionMain from "../../components/SectionMain";
-import CardBox from "../../components/CardBox";
-import BaseButton from "../../components/BaseButton";
-import BaseDivider from "../../components/BaseDivider";
-import {mdiChartTimelineVariant} from "@mdi/js";
-import {SwitchField} from "../../components/SwitchField";
-import FormField from "../../components/FormField";
-
-
-const DealsView = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const { deals } = useAppSelector((state) => state.deals)
-
-
- const { id } = router.query;
-
- function removeLastCharacter(str) {
- console.log(str,`str`)
- return str.slice(0, -1);
- }
-
- useEffect(() => {
- dispatch(fetch({ id }));
- }, [dispatch, id]);
-
-
- return (
- <>
-
- {getPageTitle('View deals')}
-
-
-
-
-
-
-
-
-
-
-
DealName
-
{deals?.name}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Stage
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{deals?.stage?.name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Owner
-
-
-
{deals?.owner?.firstName ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Account
-
-
-
-
-
-
-
-
-
{deals?.account?.name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
PrimaryContact
-
-
-
-
-
-
-
-
-
-
-
{deals?.primary_contact?.full_name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
OriginatingLead
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{deals?.originating_lead?.lead_name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Amount
-
{deals?.amount || 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Currency
-
{deals?.currency}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {deals.expected_close_at ? : No ExpectedCloseDate
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {deals.closed_at ? : No ClosedDate
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
DealStatus
-
{deals?.deal_status ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {deals.last_activity_at ? : No LastActivityAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {deals.next_follow_up_at ? : No NextFollow-upAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Description
- {deals.description
- ?
- :
No data
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <>
- Activities Deal
-
-
-
-
-
-
-
- | ActivityType |
-
-
-
- Subject |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ActivityAt |
-
-
-
- DueAt |
-
-
-
- CompletedAt |
-
-
-
- Status |
-
-
-
- Priority |
-
-
-
-
-
-
-
- {deals.activities_deal && Array.isArray(deals.activities_deal) &&
- deals.activities_deal.map((item: any) => (
- router.push(`/activities/activities-view/?id=${item.id}`)}>
-
-
- |
- { item.activity_type }
- |
-
-
-
-
- { item.subject }
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.activity_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.due_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.completed_at) }
- |
-
-
-
-
- { item.status }
- |
-
-
-
-
- { item.priority }
- |
-
-
-
-
-
- ))}
-
-
-
- {!deals?.activities_deal?.length && No data
}
-
- >
-
-
-
-
-
- router.push('/deals/deals-list')}
- />
-
-
- >
- );
-};
-
-DealsView.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default DealsView;
\ No newline at end of file
diff --git a/frontend/src/pages/lead_sources/[lead_sourcesId].tsx b/frontend/src/pages/lead_sources/[lead_sourcesId].tsx
deleted file mode 100644
index 9b14abd..0000000
--- a/frontend/src/pages/lead_sources/[lead_sourcesId].tsx
+++ /dev/null
@@ -1,311 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/lead_sources/lead_sourcesSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditLead_sources = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_active: false,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- description: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { lead_sources } = useAppSelector((state) => state.lead_sources)
-
-
- const { lead_sourcesId } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: lead_sourcesId }))
- }, [lead_sourcesId])
-
- useEffect(() => {
- if (typeof lead_sources === 'object') {
- setInitialValues(lead_sources)
- }
- }, [lead_sources])
-
- useEffect(() => {
- if (typeof lead_sources === 'object') {
-
- const newInitialVal = {...initVals};
-
- Object.keys(initVals).forEach(el => newInitialVal[el] = (lead_sources)[el])
-
- setInitialValues(newInitialVal);
- }
- }, [lead_sources])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: lead_sourcesId, data }))
- await router.push('/lead_sources/lead_sources-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit lead_sources')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditLead_sources.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditLead_sources
diff --git a/frontend/src/pages/lead_sources/lead_sources-edit.tsx b/frontend/src/pages/lead_sources/lead_sources-edit.tsx
deleted file mode 100644
index 5413ec8..0000000
--- a/frontend/src/pages/lead_sources/lead_sources-edit.tsx
+++ /dev/null
@@ -1,308 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/lead_sources/lead_sourcesSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditLead_sourcesPage = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_active: false,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- description: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { lead_sources } = useAppSelector((state) => state.lead_sources)
-
-
- const { id } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: id }))
- }, [id])
-
- useEffect(() => {
- if (typeof lead_sources === 'object') {
- setInitialValues(lead_sources)
- }
- }, [lead_sources])
-
- useEffect(() => {
- if (typeof lead_sources === 'object') {
- const newInitialVal = {...initVals};
- Object.keys(initVals).forEach(el => newInitialVal[el] = (lead_sources)[el])
- setInitialValues(newInitialVal);
- }
- }, [lead_sources])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: id, data }))
- await router.push('/lead_sources/lead_sources-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit lead_sources')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditLead_sourcesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditLead_sourcesPage
diff --git a/frontend/src/pages/lead_sources/lead_sources-list.tsx b/frontend/src/pages/lead_sources/lead_sources-list.tsx
deleted file mode 100644
index 5086d83..0000000
--- a/frontend/src/pages/lead_sources/lead_sources-list.tsx
+++ /dev/null
@@ -1,166 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableLead_sources from '../../components/Lead_sources/TableLead_sources'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/lead_sources/lead_sourcesSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const Lead_sourcesTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'SourceName', title: 'name'},{label: 'Description', title: 'description'},
-
-
-
-
-
-
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_LEAD_SOURCES');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getLead_sourcesCSV = async () => {
- const response = await axios({url: '/lead_sources?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'lead_sourcesCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Lead_sources')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
- Switch to Table
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-Lead_sourcesTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default Lead_sourcesTablesPage
diff --git a/frontend/src/pages/lead_sources/lead_sources-new.tsx b/frontend/src/pages/lead_sources/lead_sources-new.tsx
deleted file mode 100644
index 863ef55..0000000
--- a/frontend/src/pages/lead_sources/lead_sources-new.tsx
+++ /dev/null
@@ -1,239 +0,0 @@
-import { mdiAccount, mdiChartTimelineVariant, mdiMail, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SwitchField } from '../../components/SwitchField'
-
-import { SelectField } from '../../components/SelectField'
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import {RichTextField} from "../../components/RichTextField";
-
-import { create } from '../../stores/lead_sources/lead_sourcesSlice'
-import { useAppDispatch } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import moment from 'moment';
-
-const initialValues = {
-
-
- name: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_active: false,
-
-
-
-
-
-
-
-
-
-
- description: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-}
-
-
-const Lead_sourcesNew = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
-
-
-
-
- const handleSubmit = async (data) => {
- await dispatch(create(data))
- await router.push('/lead_sources/lead_sources-list')
- }
- return (
- <>
-
- {getPageTitle('New Item')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-Lead_sourcesNew.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default Lead_sourcesNew
diff --git a/frontend/src/pages/lead_sources/lead_sources-table.tsx b/frontend/src/pages/lead_sources/lead_sources-table.tsx
deleted file mode 100644
index a115fab..0000000
--- a/frontend/src/pages/lead_sources/lead_sources-table.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableLead_sources from '../../components/Lead_sources/TableLead_sources'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/lead_sources/lead_sourcesSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const Lead_sourcesTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'SourceName', title: 'name'},{label: 'Description', title: 'description'},
-
-
-
-
-
-
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_LEAD_SOURCES');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getLead_sourcesCSV = async () => {
- const response = await axios({url: '/lead_sources?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'lead_sourcesCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Lead_sources')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
-
- Back to
list
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-Lead_sourcesTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default Lead_sourcesTablesPage
diff --git a/frontend/src/pages/lead_sources/lead_sources-view.tsx b/frontend/src/pages/lead_sources/lead_sources-view.tsx
deleted file mode 100644
index 07f7cc7..0000000
--- a/frontend/src/pages/lead_sources/lead_sources-view.tsx
+++ /dev/null
@@ -1,320 +0,0 @@
-import React, { ReactElement, useEffect } from 'react';
-import Head from 'next/head'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import {useRouter} from "next/router";
-import { fetch } from '../../stores/lead_sources/lead_sourcesSlice'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-import LayoutAuthenticated from "../../layouts/Authenticated";
-import {getPageTitle} from "../../config";
-import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton";
-import SectionMain from "../../components/SectionMain";
-import CardBox from "../../components/CardBox";
-import BaseButton from "../../components/BaseButton";
-import BaseDivider from "../../components/BaseDivider";
-import {mdiChartTimelineVariant} from "@mdi/js";
-import {SwitchField} from "../../components/SwitchField";
-import FormField from "../../components/FormField";
-
-
-const Lead_sourcesView = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const { lead_sources } = useAppSelector((state) => state.lead_sources)
-
-
- const { id } = router.query;
-
- function removeLastCharacter(str) {
- console.log(str,`str`)
- return str.slice(0, -1);
- }
-
- useEffect(() => {
- dispatch(fetch({ id }));
- }, [dispatch, id]);
-
-
- return (
- <>
-
- {getPageTitle('View lead_sources')}
-
-
-
-
-
-
-
-
-
-
-
SourceName
-
{lead_sources?.name}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- null}}
- disabled
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <>
- Leads Source
-
-
-
-
-
-
-
- | LeadName |
-
-
-
- CompanyName |
-
-
-
- Email |
-
-
-
- Phone |
-
-
-
-
-
-
-
- LeadStatus |
-
-
-
- LeadRating |
-
-
-
-
-
- LastContactedAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
-
-
-
-
- {lead_sources.leads_source && Array.isArray(lead_sources.leads_source) &&
- lead_sources.leads_source.map((item: any) => (
- router.push(`/leads/leads-view/?id=${item.id}`)}>
-
-
- |
- { item.lead_name }
- |
-
-
-
-
- { item.company_name }
- |
-
-
-
-
- { item.email }
- |
-
-
-
-
- { item.phone }
- |
-
-
-
-
-
-
-
-
- { item.lead_status }
- |
-
-
-
-
- { item.lead_rating }
- |
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_contacted_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
-
-
-
-
- ))}
-
-
-
- {!lead_sources?.leads_source?.length && No data
}
-
- >
-
-
-
-
-
-
-
-
- router.push('/lead_sources/lead_sources-list')}
- />
-
-
- >
- );
-};
-
-Lead_sourcesView.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default Lead_sourcesView;
\ No newline at end of file
diff --git a/frontend/src/pages/leads/[leadsId].tsx b/frontend/src/pages/leads/[leadsId].tsx
deleted file mode 100644
index d9e1811..0000000
--- a/frontend/src/pages/leads/[leadsId].tsx
+++ /dev/null
@@ -1,1096 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/leads/leadsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditLeads = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'lead_name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'company_name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'email': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'phone': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- source: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- lead_status: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- lead_rating: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- notes: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_contacted_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- primary_contact: null,
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { leads } = useAppSelector((state) => state.leads)
-
-
- const { leadsId } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: leadsId }))
- }, [leadsId])
-
- useEffect(() => {
- if (typeof leads === 'object') {
- setInitialValues(leads)
- }
- }, [leads])
-
- useEffect(() => {
- if (typeof leads === 'object') {
-
- const newInitialVal = {...initVals};
-
- Object.keys(initVals).forEach(el => newInitialVal[el] = (leads)[el])
-
- setInitialValues(newInitialVal);
- }
- }, [leads])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: leadsId, data }))
- await router.push('/leads/leads-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit leads')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditLeads.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditLeads
diff --git a/frontend/src/pages/leads/leads-edit.tsx b/frontend/src/pages/leads/leads-edit.tsx
deleted file mode 100644
index 34ab7f1..0000000
--- a/frontend/src/pages/leads/leads-edit.tsx
+++ /dev/null
@@ -1,1093 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/leads/leadsSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditLeadsPage = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'lead_name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'company_name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'email': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'phone': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- source: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- lead_status: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- lead_rating: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- notes: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_contacted_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: new Date(),
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: null,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- primary_contact: null,
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { leads } = useAppSelector((state) => state.leads)
-
-
- const { id } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: id }))
- }, [id])
-
- useEffect(() => {
- if (typeof leads === 'object') {
- setInitialValues(leads)
- }
- }, [leads])
-
- useEffect(() => {
- if (typeof leads === 'object') {
- const newInitialVal = {...initVals};
- Object.keys(initVals).forEach(el => newInitialVal[el] = (leads)[el])
- setInitialValues(newInitialVal);
- }
- }, [leads])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: id, data }))
- await router.push('/leads/leads-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit leads')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditLeadsPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditLeadsPage
diff --git a/frontend/src/pages/leads/leads-list.tsx b/frontend/src/pages/leads/leads-list.tsx
deleted file mode 100644
index 3435a55..0000000
--- a/frontend/src/pages/leads/leads-list.tsx
+++ /dev/null
@@ -1,178 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableLeads from '../../components/Leads/TableLeads'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/leads/leadsSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const LeadsTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'LeadName', title: 'lead_name'},{label: 'CompanyName', title: 'company_name'},{label: 'Email', title: 'email'},{label: 'Phone', title: 'phone'},{label: 'Notes', title: 'notes'},
-
-
- {label: 'LastContactedAt', title: 'last_contacted_at', date: 'true'},{label: 'NextFollow-upAt', title: 'next_follow_up_at', date: 'true'},
-
-
- {label: 'Owner', title: 'owner'},
-
-
-
- {label: 'Source', title: 'source'},
-
-
-
- {label: 'LinkedAccount', title: 'account'},
-
-
-
- {label: 'PrimaryContact', title: 'primary_contact'},
-
-
-
- {label: 'LeadStatus', title: 'lead_status', type: 'enum', options: ['new','contacted','qualified','unqualified','converted']},{label: 'LeadRating', title: 'lead_rating', type: 'enum', options: ['cold','warm','hot']},
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_LEADS');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getLeadsCSV = async () => {
- const response = await axios({url: '/leads?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'leadsCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Leads')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-LeadsTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default LeadsTablesPage
diff --git a/frontend/src/pages/leads/leads-new.tsx b/frontend/src/pages/leads/leads-new.tsx
deleted file mode 100644
index 0cca497..0000000
--- a/frontend/src/pages/leads/leads-new.tsx
+++ /dev/null
@@ -1,748 +0,0 @@
-import { mdiAccount, mdiChartTimelineVariant, mdiMail, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SwitchField } from '../../components/SwitchField'
-
-import { SelectField } from '../../components/SelectField'
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import {RichTextField} from "../../components/RichTextField";
-
-import { create } from '../../stores/leads/leadsSlice'
-import { useAppDispatch } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import moment from 'moment';
-
-const initialValues = {
-
-
- lead_name: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- company_name: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- email: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- phone: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- source: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
- lead_status: 'new',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- lead_rating: 'cold',
-
-
-
-
-
-
-
-
-
- notes: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_contacted_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- next_follow_up_at: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- primary_contact: '',
-
-
-
-}
-
-
-const LeadsNew = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
-
-
-
-
- const handleSubmit = async (data) => {
- await dispatch(create(data))
- await router.push('/leads/leads-list')
- }
- return (
- <>
-
- {getPageTitle('New Item')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-LeadsNew.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default LeadsNew
diff --git a/frontend/src/pages/leads/leads-table.tsx b/frontend/src/pages/leads/leads-table.tsx
deleted file mode 100644
index 0fc92f8..0000000
--- a/frontend/src/pages/leads/leads-table.tsx
+++ /dev/null
@@ -1,180 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TableLeads from '../../components/Leads/TableLeads'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/leads/leadsSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const LeadsTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'LeadName', title: 'lead_name'},{label: 'CompanyName', title: 'company_name'},{label: 'Email', title: 'email'},{label: 'Phone', title: 'phone'},{label: 'Notes', title: 'notes'},
-
-
- {label: 'LastContactedAt', title: 'last_contacted_at', date: 'true'},{label: 'NextFollow-upAt', title: 'next_follow_up_at', date: 'true'},
-
-
- {label: 'Owner', title: 'owner'},
-
-
-
- {label: 'Source', title: 'source'},
-
-
-
- {label: 'LinkedAccount', title: 'account'},
-
-
-
- {label: 'PrimaryContact', title: 'primary_contact'},
-
-
-
- {label: 'LeadStatus', title: 'lead_status', type: 'enum', options: ['new','contacted','qualified','unqualified','converted']},{label: 'LeadRating', title: 'lead_rating', type: 'enum', options: ['cold','warm','hot']},
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_LEADS');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getLeadsCSV = async () => {
- const response = await axios({url: '/leads?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'leadsCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Leads')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
-
- Back to
table
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-LeadsTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default LeadsTablesPage
diff --git a/frontend/src/pages/leads/leads-view.tsx b/frontend/src/pages/leads/leads-view.tsx
deleted file mode 100644
index b13867d..0000000
--- a/frontend/src/pages/leads/leads-view.tsx
+++ /dev/null
@@ -1,892 +0,0 @@
-import React, { ReactElement, useEffect } from 'react';
-import Head from 'next/head'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import {useRouter} from "next/router";
-import { fetch } from '../../stores/leads/leadsSlice'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-import LayoutAuthenticated from "../../layouts/Authenticated";
-import {getPageTitle} from "../../config";
-import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton";
-import SectionMain from "../../components/SectionMain";
-import CardBox from "../../components/CardBox";
-import BaseButton from "../../components/BaseButton";
-import BaseDivider from "../../components/BaseDivider";
-import {mdiChartTimelineVariant} from "@mdi/js";
-import {SwitchField} from "../../components/SwitchField";
-import FormField from "../../components/FormField";
-
-
-const LeadsView = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const { leads } = useAppSelector((state) => state.leads)
-
-
- const { id } = router.query;
-
- function removeLastCharacter(str) {
- console.log(str,`str`)
- return str.slice(0, -1);
- }
-
- useEffect(() => {
- dispatch(fetch({ id }));
- }, [dispatch, id]);
-
-
- return (
- <>
-
- {getPageTitle('View leads')}
-
-
-
-
-
-
-
-
-
-
-
LeadName
-
{leads?.lead_name}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
CompanyName
-
{leads?.company_name}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Email
-
{leads?.email}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Phone
-
{leads?.phone}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Owner
-
-
-
{leads?.owner?.firstName ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Source
-
-
-
-
-
-
-
-
-
-
-
-
-
{leads?.source?.name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
LeadStatus
-
{leads?.lead_status ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
LeadRating
-
{leads?.lead_rating ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Notes
- {leads.notes
- ?
- :
No data
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {leads.last_contacted_at ? : No LastContactedAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {leads.next_follow_up_at ? : No NextFollow-upAt
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
LinkedAccount
-
-
-
-
-
-
-
-
-
{leads?.account?.name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
PrimaryContact
-
-
-
-
-
-
-
-
-
-
-
{leads?.primary_contact?.full_name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <>
- Deals OriginatingLead
-
-
-
-
-
-
-
- | DealName |
-
-
-
-
-
-
-
-
-
-
-
-
-
- Amount |
-
-
-
- Currency |
-
-
-
- ExpectedCloseDate |
-
-
-
- ClosedDate |
-
-
-
- DealStatus |
-
-
-
- LossReason |
-
-
-
- LastActivityAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
-
-
- {leads.deals_originating_lead && Array.isArray(leads.deals_originating_lead) &&
- leads.deals_originating_lead.map((item: any) => (
- router.push(`/deals/deals-view/?id=${item.id}`)}>
-
-
- |
- { item.name }
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { item.amount }
- |
-
-
-
-
- { item.currency }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.expected_close_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.closed_at) }
- |
-
-
-
-
- { item.deal_status }
- |
-
-
-
-
- { item.loss_reason }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_activity_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
-
-
- ))}
-
-
-
- {!leads?.deals_originating_lead?.length && No data
}
-
- >
-
-
- <>
- Activities Lead
-
-
-
-
-
-
-
- | ActivityType |
-
-
-
- Subject |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ActivityAt |
-
-
-
- DueAt |
-
-
-
- CompletedAt |
-
-
-
- Status |
-
-
-
- Priority |
-
-
-
-
-
-
-
- {leads.activities_lead && Array.isArray(leads.activities_lead) &&
- leads.activities_lead.map((item: any) => (
- router.push(`/activities/activities-view/?id=${item.id}`)}>
-
-
- |
- { item.activity_type }
- |
-
-
-
-
- { item.subject }
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.activity_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.due_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.completed_at) }
- |
-
-
-
-
- { item.status }
- |
-
-
-
-
- { item.priority }
- |
-
-
-
-
-
- ))}
-
-
-
- {!leads?.activities_lead?.length && No data
}
-
- >
-
-
-
-
-
- router.push('/leads/leads-list')}
- />
-
-
- >
- );
-};
-
-LeadsView.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default LeadsView;
\ No newline at end of file
diff --git a/frontend/src/pages/login.tsx b/frontend/src/pages/login.tsx
index 5fcbf02..85c9427 100644
--- a/frontend/src/pages/login.tsx
+++ b/frontend/src/pages/login.tsx
@@ -44,7 +44,7 @@ export default function Login() {
password: 'f76d928f',
remember: true })
- const title = 'Sales Pipeline CRM'
+ const title = 'Coaching SaaS Workspace'
// Fetch Pexels image/video
useEffect( () => {
diff --git a/frontend/src/pages/pipeline_stages/[pipeline_stagesId].tsx b/frontend/src/pages/pipeline_stages/[pipeline_stagesId].tsx
deleted file mode 100644
index 2736682..0000000
--- a/frontend/src/pages/pipeline_stages/[pipeline_stagesId].tsx
+++ /dev/null
@@ -1,511 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/pipeline_stages/pipeline_stagesSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditPipeline_stages = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- sort_order: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'win_probability': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_won: false,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_lost: false,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_active: false,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { pipeline_stages } = useAppSelector((state) => state.pipeline_stages)
-
-
- const { pipeline_stagesId } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: pipeline_stagesId }))
- }, [pipeline_stagesId])
-
- useEffect(() => {
- if (typeof pipeline_stages === 'object') {
- setInitialValues(pipeline_stages)
- }
- }, [pipeline_stages])
-
- useEffect(() => {
- if (typeof pipeline_stages === 'object') {
-
- const newInitialVal = {...initVals};
-
- Object.keys(initVals).forEach(el => newInitialVal[el] = (pipeline_stages)[el])
-
- setInitialValues(newInitialVal);
- }
- }, [pipeline_stages])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: pipeline_stagesId, data }))
- await router.push('/pipeline_stages/pipeline_stages-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit pipeline_stages')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditPipeline_stages.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditPipeline_stages
diff --git a/frontend/src/pages/pipeline_stages/pipeline_stages-edit.tsx b/frontend/src/pages/pipeline_stages/pipeline_stages-edit.tsx
deleted file mode 100644
index c873c22..0000000
--- a/frontend/src/pages/pipeline_stages/pipeline_stages-edit.tsx
+++ /dev/null
@@ -1,508 +0,0 @@
-import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement, useEffect, useState } from 'react'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SelectField } from "../../components/SelectField";
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import { SwitchField } from '../../components/SwitchField'
-import {RichTextField} from "../../components/RichTextField";
-
-import { update, fetch } from '../../stores/pipeline_stages/pipeline_stagesSlice'
-import { useAppDispatch, useAppSelector } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-
-
-
-const EditPipeline_stagesPage = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const initVals = {
-
-
- 'name': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- sort_order: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 'win_probability': '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_won: false,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_lost: false,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_active: false,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const [initialValues, setInitialValues] = useState(initVals)
-
- const { pipeline_stages } = useAppSelector((state) => state.pipeline_stages)
-
-
- const { id } = router.query
-
- useEffect(() => {
- dispatch(fetch({ id: id }))
- }, [id])
-
- useEffect(() => {
- if (typeof pipeline_stages === 'object') {
- setInitialValues(pipeline_stages)
- }
- }, [pipeline_stages])
-
- useEffect(() => {
- if (typeof pipeline_stages === 'object') {
- const newInitialVal = {...initVals};
- Object.keys(initVals).forEach(el => newInitialVal[el] = (pipeline_stages)[el])
- setInitialValues(newInitialVal);
- }
- }, [pipeline_stages])
-
- const handleSubmit = async (data) => {
- await dispatch(update({ id: id, data }))
- await router.push('/pipeline_stages/pipeline_stages-list')
- }
-
- return (
- <>
-
- {getPageTitle('Edit pipeline_stages')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-EditPipeline_stagesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default EditPipeline_stagesPage
diff --git a/frontend/src/pages/pipeline_stages/pipeline_stages-list.tsx b/frontend/src/pages/pipeline_stages/pipeline_stages-list.tsx
deleted file mode 100644
index f71115d..0000000
--- a/frontend/src/pages/pipeline_stages/pipeline_stages-list.tsx
+++ /dev/null
@@ -1,166 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TablePipeline_stages from '../../components/Pipeline_stages/TablePipeline_stages'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/pipeline_stages/pipeline_stagesSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const Pipeline_stagesTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'StageName', title: 'name'},
- {label: 'SortOrder', title: 'sort_order', number: 'true'},
- {label: 'WinProbability', title: 'win_probability', number: 'true'},
-
-
-
-
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_PIPELINE_STAGES');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getPipeline_stagesCSV = async () => {
- const response = await axios({url: '/pipeline_stages?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'pipeline_stagesCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Pipeline_stages')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
- Switch to Table
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-Pipeline_stagesTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default Pipeline_stagesTablesPage
diff --git a/frontend/src/pages/pipeline_stages/pipeline_stages-new.tsx b/frontend/src/pages/pipeline_stages/pipeline_stages-new.tsx
deleted file mode 100644
index dbdd0c1..0000000
--- a/frontend/src/pages/pipeline_stages/pipeline_stages-new.tsx
+++ /dev/null
@@ -1,397 +0,0 @@
-import { mdiAccount, mdiChartTimelineVariant, mdiMail, mdiUpload } from '@mdi/js'
-import Head from 'next/head'
-import React, { ReactElement } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-
-import { Field, Form, Formik } from 'formik'
-import FormField from '../../components/FormField'
-import BaseDivider from '../../components/BaseDivider'
-import BaseButtons from '../../components/BaseButtons'
-import BaseButton from '../../components/BaseButton'
-import FormCheckRadio from '../../components/FormCheckRadio'
-import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
-import FormFilePicker from '../../components/FormFilePicker'
-import FormImagePicker from '../../components/FormImagePicker'
-import { SwitchField } from '../../components/SwitchField'
-
-import { SelectField } from '../../components/SelectField'
-import { SelectFieldMany } from "../../components/SelectFieldMany";
-import {RichTextField} from "../../components/RichTextField";
-
-import { create } from '../../stores/pipeline_stages/pipeline_stagesSlice'
-import { useAppDispatch } from '../../stores/hooks'
-import { useRouter } from 'next/router'
-import moment from 'moment';
-
-const initialValues = {
-
-
- name: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- sort_order: '',
-
-
-
-
-
-
-
-
-
-
-
-
- win_probability: '',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_won: false,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_lost: false,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- is_active: false,
-
-
-
-
-
-
-
-
-}
-
-
-const Pipeline_stagesNew = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
-
-
-
-
- const handleSubmit = async (data) => {
- await dispatch(create(data))
- await router.push('/pipeline_stages/pipeline_stages-list')
- }
- return (
- <>
-
- {getPageTitle('New Item')}
-
-
-
- {''}
-
-
- handleSubmit(values)}
- >
-
-
-
-
- >
- )
-}
-
-Pipeline_stagesNew.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default Pipeline_stagesNew
diff --git a/frontend/src/pages/pipeline_stages/pipeline_stages-table.tsx b/frontend/src/pages/pipeline_stages/pipeline_stages-table.tsx
deleted file mode 100644
index 32a4d8d..0000000
--- a/frontend/src/pages/pipeline_stages/pipeline_stages-table.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-import { mdiChartTimelineVariant } from '@mdi/js'
-import Head from 'next/head'
-import { uniqueId } from 'lodash';
-import React, { ReactElement, useState } from 'react'
-import CardBox from '../../components/CardBox'
-import LayoutAuthenticated from '../../layouts/Authenticated'
-import SectionMain from '../../components/SectionMain'
-import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
-import { getPageTitle } from '../../config'
-import TablePipeline_stages from '../../components/Pipeline_stages/TablePipeline_stages'
-import BaseButton from '../../components/BaseButton'
-import axios from "axios";
-import Link from "next/link";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import CardBoxModal from "../../components/CardBoxModal";
-import DragDropFilePicker from "../../components/DragDropFilePicker";
-import {setRefetch, uploadCsv} from '../../stores/pipeline_stages/pipeline_stagesSlice';
-
-
-import {hasPermission} from "../../helpers/userPermissions";
-
-
-
-const Pipeline_stagesTablesPage = () => {
- const [filterItems, setFilterItems] = useState([]);
- const [csvFile, setCsvFile] = useState(null);
- const [isModalActive, setIsModalActive] = useState(false);
- const [showTableView, setShowTableView] = useState(false);
-
-
- const { currentUser } = useAppSelector((state) => state.auth);
-
-
- const dispatch = useAppDispatch();
-
-
- const [filters] = useState([{label: 'StageName', title: 'name'},
- {label: 'SortOrder', title: 'sort_order', number: 'true'},
- {label: 'WinProbability', title: 'win_probability', number: 'true'},
-
-
-
-
- ]);
-
- const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_PIPELINE_STAGES');
-
-
- const addFilter = () => {
- const newItem = {
- id: uniqueId(),
- fields: {
- filterValue: '',
- filterValueFrom: '',
- filterValueTo: '',
- selectedField: '',
- },
- };
- newItem.fields.selectedField = filters[0].title;
- setFilterItems([...filterItems, newItem]);
- };
-
- const getPipeline_stagesCSV = async () => {
- const response = await axios({url: '/pipeline_stages?filetype=csv', method: 'GET',responseType: 'blob'});
- const type = response.headers['content-type']
- const blob = new Blob([response.data], { type: type })
- const link = document.createElement('a')
- link.href = window.URL.createObjectURL(blob)
- link.download = 'pipeline_stagesCSV.csv'
- link.click()
- };
-
- const onModalConfirm = async () => {
- if (!csvFile) return;
- await dispatch(uploadCsv(csvFile));
- dispatch(setRefetch(true));
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- const onModalCancel = () => {
- setCsvFile(null);
- setIsModalActive(false);
- };
-
- return (
- <>
-
- {getPageTitle('Pipeline_stages')}
-
-
-
- {''}
-
-
-
- {hasCreatePermission && }
-
-
-
-
- {hasCreatePermission && (
- setIsModalActive(true)}
- />
- )}
-
-
-
-
-
- Back to
list
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-Pipeline_stagesTablesPage.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default Pipeline_stagesTablesPage
diff --git a/frontend/src/pages/pipeline_stages/pipeline_stages-view.tsx b/frontend/src/pages/pipeline_stages/pipeline_stages-view.tsx
deleted file mode 100644
index 7766606..0000000
--- a/frontend/src/pages/pipeline_stages/pipeline_stages-view.tsx
+++ /dev/null
@@ -1,437 +0,0 @@
-import React, { ReactElement, useEffect } from 'react';
-import Head from 'next/head'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import {useRouter} from "next/router";
-import { fetch } from '../../stores/pipeline_stages/pipeline_stagesSlice'
-import {saveFile} from "../../helpers/fileSaver";
-import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-import LayoutAuthenticated from "../../layouts/Authenticated";
-import {getPageTitle} from "../../config";
-import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton";
-import SectionMain from "../../components/SectionMain";
-import CardBox from "../../components/CardBox";
-import BaseButton from "../../components/BaseButton";
-import BaseDivider from "../../components/BaseDivider";
-import {mdiChartTimelineVariant} from "@mdi/js";
-import {SwitchField} from "../../components/SwitchField";
-import FormField from "../../components/FormField";
-
-
-const Pipeline_stagesView = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const { pipeline_stages } = useAppSelector((state) => state.pipeline_stages)
-
-
- const { id } = router.query;
-
- function removeLastCharacter(str) {
- console.log(str,`str`)
- return str.slice(0, -1);
- }
-
- useEffect(() => {
- dispatch(fetch({ id }));
- }, [dispatch, id]);
-
-
- return (
- <>
-
- {getPageTitle('View pipeline_stages')}
-
-
-
-
-
-
-
-
-
-
-
StageName
-
{pipeline_stages?.name}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
SortOrder
-
{pipeline_stages?.sort_order || 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
WinProbability
-
{pipeline_stages?.win_probability || 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- null}}
- disabled
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- null}}
- disabled
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- null}}
- disabled
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <>
- Deals Stage
-
-
-
-
-
-
-
- | DealName |
-
-
-
-
-
-
-
-
-
-
-
-
-
- Amount |
-
-
-
- Currency |
-
-
-
- ExpectedCloseDate |
-
-
-
- ClosedDate |
-
-
-
- DealStatus |
-
-
-
- LossReason |
-
-
-
- LastActivityAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
-
-
- {pipeline_stages.deals_stage && Array.isArray(pipeline_stages.deals_stage) &&
- pipeline_stages.deals_stage.map((item: any) => (
- router.push(`/deals/deals-view/?id=${item.id}`)}>
-
-
- |
- { item.name }
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { item.amount }
- |
-
-
-
-
- { item.currency }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.expected_close_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.closed_at) }
- |
-
-
-
-
- { item.deal_status }
- |
-
-
-
-
- { item.loss_reason }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_activity_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
-
-
- ))}
-
-
-
- {!pipeline_stages?.deals_stage?.length && No data
}
-
- >
-
-
-
-
-
-
- router.push('/pipeline_stages/pipeline_stages-list')}
- />
-
-
- >
- );
-};
-
-Pipeline_stagesView.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
-
-export default Pipeline_stagesView;
\ No newline at end of file
diff --git a/frontend/src/pages/privacy-policy.tsx b/frontend/src/pages/privacy-policy.tsx
index e1c7192..3f5c997 100644
--- a/frontend/src/pages/privacy-policy.tsx
+++ b/frontend/src/pages/privacy-policy.tsx
@@ -5,7 +5,7 @@ import LayoutGuest from '../layouts/Guest';
import { getPageTitle } from '../config';
export default function PrivacyPolicy() {
- const title = 'Sales Pipeline CRM'
+ const title = 'Coaching SaaS Workspace'
const [projectUrl, setProjectUrl] = useState('');
useEffect(() => {
diff --git a/frontend/src/pages/terms-of-use.tsx b/frontend/src/pages/terms-of-use.tsx
index cf836e2..ca678f8 100644
--- a/frontend/src/pages/terms-of-use.tsx
+++ b/frontend/src/pages/terms-of-use.tsx
@@ -5,7 +5,7 @@ import LayoutGuest from '../layouts/Guest';
import { getPageTitle } from '../config';
export default function PrivacyPolicy() {
- const title = 'Sales Pipeline CRM';
+ const title = 'Coaching SaaS Workspace';
const [projectUrl, setProjectUrl] = useState('');
useEffect(() => {
diff --git a/frontend/src/pages/users/users-view.tsx b/frontend/src/pages/users/users-view.tsx
index 7953b58..f3a56aa 100644
--- a/frontend/src/pages/users/users-view.tsx
+++ b/frontend/src/pages/users/users-view.tsx
@@ -1,1099 +1,86 @@
import React, { ReactElement, useEffect } from 'react';
-import Head from 'next/head'
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import dayjs from "dayjs";
-import {useAppDispatch, useAppSelector} from "../../stores/hooks";
-import {useRouter} from "next/router";
-import { fetch } from '../../stores/users/usersSlice'
-import {saveFile} from "../../helpers/fileSaver";
+import Head from 'next/head';
+import { useRouter } from 'next/router';
+import { mdiAccountCircle } from '@mdi/js';
+import { useAppDispatch, useAppSelector } from '../../stores/hooks';
+import { fetch } from '../../stores/users/usersSlice';
+import LayoutAuthenticated from '../../layouts/Authenticated';
+import { getPageTitle } from '../../config';
+import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton';
+import SectionMain from '../../components/SectionMain';
+import CardBox from '../../components/CardBox';
+import BaseButton from '../../components/BaseButton';
+import BaseDivider from '../../components/BaseDivider';
import dataFormatter from '../../helpers/dataFormatter';
-import ImageField from "../../components/ImageField";
-import LayoutAuthenticated from "../../layouts/Authenticated";
-import {getPageTitle} from "../../config";
-import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton";
-import SectionMain from "../../components/SectionMain";
-import CardBox from "../../components/CardBox";
-import BaseButton from "../../components/BaseButton";
-import BaseDivider from "../../components/BaseDivider";
-import {mdiChartTimelineVariant} from "@mdi/js";
-import {SwitchField} from "../../components/SwitchField";
-import FormField from "../../components/FormField";
-
const UsersView = () => {
- const router = useRouter()
- const dispatch = useAppDispatch()
- const { users } = useAppSelector((state) => state.users)
-
-
- const { id } = router.query;
-
- function removeLastCharacter(str) {
- console.log(str,`str`)
- return str.slice(0, -1);
- }
-
- useEffect(() => {
- dispatch(fetch({ id }));
- }, [dispatch, id]);
-
-
- return (
- <>
-
- {getPageTitle('View users')}
-
-
-
-
-
-
-
-
-
-
-
First Name
-
{users?.firstName}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Last Name
-
{users?.lastName}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Phone Number
-
{users?.phoneNumber}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
E-Mail
-
{users?.email}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- null}}
- disabled
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Avatar
- {users?.avatar?.length
- ? (
-
- ) :
No Avatar
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
App Role
-
-
-
-
-
{users?.app_role?.name ?? 'No data'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <>
- Custom Permissions
-
-
-
-
-
-
-
-
-
-
- | Name |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {users.custom_permissions && Array.isArray(users.custom_permissions) &&
- users.custom_permissions.map((item: any) => (
- router.push(`/permissions/permissions-view/?id=${item.id}`)}>
-
-
-
-
-
- |
- { item.name }
- |
-
-
-
-
-
-
-
-
-
-
-
-
- ))}
-
-
-
- {!users?.custom_permissions?.length && No data
}
-
- >
-
-
-
-
-
-
-
-
-
-
-
- <>
- Accounts Owner
-
-
-
-
-
-
-
- | AccountName |
-
-
-
- Domain |
-
-
-
- Industry |
-
-
-
- EmployeeCount |
-
-
-
- AnnualRevenue |
-
-
-
- Phone |
-
-
-
- Website |
-
-
-
- Address |
-
-
-
-
-
- AccountStatus |
-
-
-
- LastContactedAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
-
-
- {users.accounts_owner && Array.isArray(users.accounts_owner) &&
- users.accounts_owner.map((item: any) => (
- router.push(`/accounts/accounts-view/?id=${item.id}`)}>
-
-
- |
- { item.name }
- |
-
-
-
-
- { item.domain }
- |
-
-
-
-
- { item.industry }
- |
-
-
-
-
- { item.employee_count }
- |
-
-
-
-
- { item.annual_revenue }
- |
-
-
-
-
- { item.phone }
- |
-
-
-
-
- { item.website }
- |
-
-
-
-
- { item.address }
- |
-
-
-
-
-
-
- { item.account_status }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_contacted_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
-
-
- ))}
-
-
-
- {!users?.accounts_owner?.length && No data
}
-
- >
-
-
- <>
- Contacts Owner
-
-
-
-
-
-
-
- | FullName |
-
-
-
- Email |
-
-
-
- Phone |
-
-
-
- JobTitle |
-
-
-
-
-
-
-
- ContactStatus |
-
-
-
- LinkedInURL |
-
-
-
-
-
- LastContactedAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
- {users.contacts_owner && Array.isArray(users.contacts_owner) &&
- users.contacts_owner.map((item: any) => (
- router.push(`/contacts/contacts-view/?id=${item.id}`)}>
-
-
- |
- { item.full_name }
- |
-
-
-
-
- { item.email }
- |
-
-
-
-
- { item.phone }
- |
-
-
-
-
- { item.job_title }
- |
-
-
-
-
-
-
-
-
- { item.contact_status }
- |
-
-
-
-
- { item.linkedin_url }
- |
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_contacted_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
- ))}
-
-
-
- {!users?.contacts_owner?.length && No data
}
-
- >
-
-
-
- <>
- Leads Owner
-
-
-
-
-
-
-
- | LeadName |
-
-
-
- CompanyName |
-
-
-
- Email |
-
-
-
- Phone |
-
-
-
-
-
-
-
- LeadStatus |
-
-
-
- LeadRating |
-
-
-
-
-
- LastContactedAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
-
-
-
-
- {users.leads_owner && Array.isArray(users.leads_owner) &&
- users.leads_owner.map((item: any) => (
- router.push(`/leads/leads-view/?id=${item.id}`)}>
-
-
- |
- { item.lead_name }
- |
-
-
-
-
- { item.company_name }
- |
-
-
-
-
- { item.email }
- |
-
-
-
-
- { item.phone }
- |
-
-
-
-
-
-
-
-
- { item.lead_status }
- |
-
-
-
-
- { item.lead_rating }
- |
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_contacted_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
-
-
-
-
- ))}
-
-
-
- {!users?.leads_owner?.length && No data
}
-
- >
-
-
-
- <>
- Deals Owner
-
-
-
-
-
-
-
- | DealName |
-
-
-
-
-
-
-
-
-
-
-
-
-
- Amount |
-
-
-
- Currency |
-
-
-
- ExpectedCloseDate |
-
-
-
- ClosedDate |
-
-
-
- DealStatus |
-
-
-
- LossReason |
-
-
-
- LastActivityAt |
-
-
-
- NextFollow-upAt |
-
-
-
-
-
-
-
- {users.deals_owner && Array.isArray(users.deals_owner) &&
- users.deals_owner.map((item: any) => (
- router.push(`/deals/deals-view/?id=${item.id}`)}>
-
-
- |
- { item.name }
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { item.amount }
- |
-
-
-
-
- { item.currency }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.expected_close_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.closed_at) }
- |
-
-
-
-
- { item.deal_status }
- |
-
-
-
-
- { item.loss_reason }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.last_activity_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.next_follow_up_at) }
- |
-
-
-
-
-
- ))}
-
-
-
- {!users?.deals_owner?.length && No data
}
-
- >
-
-
- <>
- Activities Owner
-
-
-
-
-
-
-
- | ActivityType |
-
-
-
- Subject |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ActivityAt |
-
-
-
- DueAt |
-
-
-
- CompletedAt |
-
-
-
- Status |
-
-
-
- Priority |
-
-
-
-
-
-
-
- {users.activities_owner && Array.isArray(users.activities_owner) &&
- users.activities_owner.map((item: any) => (
- router.push(`/activities/activities-view/?id=${item.id}`)}>
-
-
- |
- { item.activity_type }
- |
-
-
-
-
- { item.subject }
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.activity_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.due_at) }
- |
-
-
-
-
- { dataFormatter.dateTimeFormatter(item.completed_at) }
- |
-
-
-
-
- { item.status }
- |
-
-
-
-
- { item.priority }
- |
-
-
-
-
-
- ))}
-
-
-
- {!users?.activities_owner?.length && No data
}
-
- >
-
-
-
-
-
- router.push('/users/users-list')}
- />
-
-
- >
- );
+ const router = useRouter();
+ const dispatch = useAppDispatch();
+ const { users } = useAppSelector((state) => state.users);
+ const { id } = router.query;
+
+ useEffect(() => {
+ dispatch(fetch({ id }));
+ }, [dispatch, id]);
+
+ return (
+ <>
+
+ {getPageTitle('View user')}
+
+
+
+
+
+
+
+
First Name
+
{users?.firstName || 'No data'}
+
+
+
Last Name
+
{users?.lastName || 'No data'}
+
+
+
Phone Number
+
{users?.phoneNumber || 'No data'}
+
+
+
E-Mail
+
{users?.email || 'No data'}
+
+
+
Disabled
+
{dataFormatter.booleanFormatter(users?.disabled)}
+
+
+
Email Verified
+
{dataFormatter.booleanFormatter(users?.emailVerified)}
+
+
+
Role
+
{users?.app_role?.name || 'No data'}
+
+
+
+
+ router.push('/users/users-list')}
+ />
+
+
+ >
+ );
};
UsersView.getLayout = function getLayout(page: ReactElement) {
- return (
-
- {page}
-
- )
-}
+ return (
+
+ {page}
+
+ );
+};
-export default UsersView;
\ No newline at end of file
+export default UsersView;
diff --git a/frontend/src/stores/accounts/accountsSlice.ts b/frontend/src/stores/accounts/accountsSlice.ts
deleted file mode 100644
index 9c7146a..0000000
--- a/frontend/src/stores/accounts/accountsSlice.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
-import axios from 'axios'
-import {fulfilledNotify, rejectNotify, resetNotify} from "../../helpers/notifyStateHandler";
-
-interface MainState {
- accounts: any
- loading: boolean
- count: number
- refetch: boolean;
- rolesWidgets: any[];
- notify: {
- showNotification: boolean
- textNotification: string
- typeNotification: string
- }
-}
-
-const initialState: MainState = {
- accounts: [],
- loading: false,
- count: 0,
- refetch: false,
- rolesWidgets: [],
- notify: {
- showNotification: false,
- textNotification: '',
- typeNotification: 'warn',
- },
-}
-
-export const fetch = createAsyncThunk('accounts/fetch', async (data: any) => {
- const { id, query } = data
- const result = await axios.get(
- `accounts${
- query || (id ? `/${id}` : '')
- }`
- )
- return id ? result.data : {rows: result.data.rows, count: result.data.count};
-})
-
-export const deleteItemsByIds = createAsyncThunk(
- 'accounts/deleteByIds',
- async (data: any, { rejectWithValue }) => {
- try {
- await axios.post('accounts/deleteByIds', { data });
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const deleteItem = createAsyncThunk('accounts/deleteAccounts', async (id: string, { rejectWithValue }) => {
- try {
- await axios.delete(`accounts/${id}`)
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const create = createAsyncThunk('accounts/createAccounts', async (data: any, { rejectWithValue }) => {
- try {
- const result = await axios.post(
- 'accounts',
- { data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const uploadCsv = createAsyncThunk(
- 'accounts/uploadCsv',
- async (file: File, { rejectWithValue }) => {
- try {
- const data = new FormData();
- data.append('file', file);
- data.append('filename', file.name);
-
- const result = await axios.post('accounts/bulk-import', data, {
- headers: {
- 'Content-Type': 'multipart/form-data',
- },
- });
-
- return result.data;
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const update = createAsyncThunk('accounts/updateAccounts', async (payload: any, { rejectWithValue }) => {
- try {
- const result = await axios.put(
- `accounts/${payload.id}`,
- { id: payload.id, data: payload.data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-
-export const accountsSlice = createSlice({
- name: 'accounts',
- initialState,
- reducers: {
- setRefetch: (state, action: PayloadAction) => {
- state.refetch = action.payload;
- },
- },
- extraReducers: (builder) => {
- builder.addCase(fetch.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(fetch.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(fetch.fulfilled, (state, action) => {
- if (action.payload.rows && action.payload.count >= 0) {
- state.accounts = action.payload.rows;
- state.count = action.payload.count;
- } else {
- state.accounts = action.payload;
- }
- state.loading = false
- })
-
- builder.addCase(deleteItemsByIds.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- });
-
- builder.addCase(deleteItemsByIds.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Accounts has been deleted');
- });
-
- builder.addCase(deleteItemsByIds.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- });
-
- builder.addCase(deleteItem.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
-
- builder.addCase(deleteItem.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Accounts'.slice(0, -1)} has been deleted`);
- })
-
- builder.addCase(deleteItem.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(create.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Accounts'.slice(0, -1)} has been created`);
- })
-
- builder.addCase(update.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(update.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Accounts'.slice(0, -1)} has been updated`);
- })
- builder.addCase(update.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(uploadCsv.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- })
- builder.addCase(uploadCsv.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Accounts has been uploaded');
- })
- builder.addCase(uploadCsv.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- })
-
-
- },
-})
-
-// Action creators are generated for each case reducer function
- export const { setRefetch } = accountsSlice.actions
-
-export default accountsSlice.reducer
diff --git a/frontend/src/stores/activities/activitiesSlice.ts b/frontend/src/stores/activities/activitiesSlice.ts
deleted file mode 100644
index 7a12c89..0000000
--- a/frontend/src/stores/activities/activitiesSlice.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
-import axios from 'axios'
-import {fulfilledNotify, rejectNotify, resetNotify} from "../../helpers/notifyStateHandler";
-
-interface MainState {
- activities: any
- loading: boolean
- count: number
- refetch: boolean;
- rolesWidgets: any[];
- notify: {
- showNotification: boolean
- textNotification: string
- typeNotification: string
- }
-}
-
-const initialState: MainState = {
- activities: [],
- loading: false,
- count: 0,
- refetch: false,
- rolesWidgets: [],
- notify: {
- showNotification: false,
- textNotification: '',
- typeNotification: 'warn',
- },
-}
-
-export const fetch = createAsyncThunk('activities/fetch', async (data: any) => {
- const { id, query } = data
- const result = await axios.get(
- `activities${
- query || (id ? `/${id}` : '')
- }`
- )
- return id ? result.data : {rows: result.data.rows, count: result.data.count};
-})
-
-export const deleteItemsByIds = createAsyncThunk(
- 'activities/deleteByIds',
- async (data: any, { rejectWithValue }) => {
- try {
- await axios.post('activities/deleteByIds', { data });
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const deleteItem = createAsyncThunk('activities/deleteActivities', async (id: string, { rejectWithValue }) => {
- try {
- await axios.delete(`activities/${id}`)
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const create = createAsyncThunk('activities/createActivities', async (data: any, { rejectWithValue }) => {
- try {
- const result = await axios.post(
- 'activities',
- { data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const uploadCsv = createAsyncThunk(
- 'activities/uploadCsv',
- async (file: File, { rejectWithValue }) => {
- try {
- const data = new FormData();
- data.append('file', file);
- data.append('filename', file.name);
-
- const result = await axios.post('activities/bulk-import', data, {
- headers: {
- 'Content-Type': 'multipart/form-data',
- },
- });
-
- return result.data;
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const update = createAsyncThunk('activities/updateActivities', async (payload: any, { rejectWithValue }) => {
- try {
- const result = await axios.put(
- `activities/${payload.id}`,
- { id: payload.id, data: payload.data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-
-export const activitiesSlice = createSlice({
- name: 'activities',
- initialState,
- reducers: {
- setRefetch: (state, action: PayloadAction) => {
- state.refetch = action.payload;
- },
- },
- extraReducers: (builder) => {
- builder.addCase(fetch.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(fetch.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(fetch.fulfilled, (state, action) => {
- if (action.payload.rows && action.payload.count >= 0) {
- state.activities = action.payload.rows;
- state.count = action.payload.count;
- } else {
- state.activities = action.payload;
- }
- state.loading = false
- })
-
- builder.addCase(deleteItemsByIds.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- });
-
- builder.addCase(deleteItemsByIds.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Activities has been deleted');
- });
-
- builder.addCase(deleteItemsByIds.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- });
-
- builder.addCase(deleteItem.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
-
- builder.addCase(deleteItem.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Activities'.slice(0, -1)} has been deleted`);
- })
-
- builder.addCase(deleteItem.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(create.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Activities'.slice(0, -1)} has been created`);
- })
-
- builder.addCase(update.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(update.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Activities'.slice(0, -1)} has been updated`);
- })
- builder.addCase(update.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(uploadCsv.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- })
- builder.addCase(uploadCsv.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Activities has been uploaded');
- })
- builder.addCase(uploadCsv.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- })
-
-
- },
-})
-
-// Action creators are generated for each case reducer function
- export const { setRefetch } = activitiesSlice.actions
-
-export default activitiesSlice.reducer
diff --git a/frontend/src/stores/contacts/contactsSlice.ts b/frontend/src/stores/contacts/contactsSlice.ts
deleted file mode 100644
index 1fa2069..0000000
--- a/frontend/src/stores/contacts/contactsSlice.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
-import axios from 'axios'
-import {fulfilledNotify, rejectNotify, resetNotify} from "../../helpers/notifyStateHandler";
-
-interface MainState {
- contacts: any
- loading: boolean
- count: number
- refetch: boolean;
- rolesWidgets: any[];
- notify: {
- showNotification: boolean
- textNotification: string
- typeNotification: string
- }
-}
-
-const initialState: MainState = {
- contacts: [],
- loading: false,
- count: 0,
- refetch: false,
- rolesWidgets: [],
- notify: {
- showNotification: false,
- textNotification: '',
- typeNotification: 'warn',
- },
-}
-
-export const fetch = createAsyncThunk('contacts/fetch', async (data: any) => {
- const { id, query } = data
- const result = await axios.get(
- `contacts${
- query || (id ? `/${id}` : '')
- }`
- )
- return id ? result.data : {rows: result.data.rows, count: result.data.count};
-})
-
-export const deleteItemsByIds = createAsyncThunk(
- 'contacts/deleteByIds',
- async (data: any, { rejectWithValue }) => {
- try {
- await axios.post('contacts/deleteByIds', { data });
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const deleteItem = createAsyncThunk('contacts/deleteContacts', async (id: string, { rejectWithValue }) => {
- try {
- await axios.delete(`contacts/${id}`)
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const create = createAsyncThunk('contacts/createContacts', async (data: any, { rejectWithValue }) => {
- try {
- const result = await axios.post(
- 'contacts',
- { data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const uploadCsv = createAsyncThunk(
- 'contacts/uploadCsv',
- async (file: File, { rejectWithValue }) => {
- try {
- const data = new FormData();
- data.append('file', file);
- data.append('filename', file.name);
-
- const result = await axios.post('contacts/bulk-import', data, {
- headers: {
- 'Content-Type': 'multipart/form-data',
- },
- });
-
- return result.data;
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const update = createAsyncThunk('contacts/updateContacts', async (payload: any, { rejectWithValue }) => {
- try {
- const result = await axios.put(
- `contacts/${payload.id}`,
- { id: payload.id, data: payload.data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-
-export const contactsSlice = createSlice({
- name: 'contacts',
- initialState,
- reducers: {
- setRefetch: (state, action: PayloadAction) => {
- state.refetch = action.payload;
- },
- },
- extraReducers: (builder) => {
- builder.addCase(fetch.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(fetch.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(fetch.fulfilled, (state, action) => {
- if (action.payload.rows && action.payload.count >= 0) {
- state.contacts = action.payload.rows;
- state.count = action.payload.count;
- } else {
- state.contacts = action.payload;
- }
- state.loading = false
- })
-
- builder.addCase(deleteItemsByIds.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- });
-
- builder.addCase(deleteItemsByIds.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Contacts has been deleted');
- });
-
- builder.addCase(deleteItemsByIds.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- });
-
- builder.addCase(deleteItem.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
-
- builder.addCase(deleteItem.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Contacts'.slice(0, -1)} has been deleted`);
- })
-
- builder.addCase(deleteItem.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(create.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Contacts'.slice(0, -1)} has been created`);
- })
-
- builder.addCase(update.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(update.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Contacts'.slice(0, -1)} has been updated`);
- })
- builder.addCase(update.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(uploadCsv.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- })
- builder.addCase(uploadCsv.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Contacts has been uploaded');
- })
- builder.addCase(uploadCsv.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- })
-
-
- },
-})
-
-// Action creators are generated for each case reducer function
- export const { setRefetch } = contactsSlice.actions
-
-export default contactsSlice.reducer
diff --git a/frontend/src/stores/deals/dealsSlice.ts b/frontend/src/stores/deals/dealsSlice.ts
deleted file mode 100644
index b3edf4e..0000000
--- a/frontend/src/stores/deals/dealsSlice.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
-import axios from 'axios'
-import {fulfilledNotify, rejectNotify, resetNotify} from "../../helpers/notifyStateHandler";
-
-interface MainState {
- deals: any
- loading: boolean
- count: number
- refetch: boolean;
- rolesWidgets: any[];
- notify: {
- showNotification: boolean
- textNotification: string
- typeNotification: string
- }
-}
-
-const initialState: MainState = {
- deals: [],
- loading: false,
- count: 0,
- refetch: false,
- rolesWidgets: [],
- notify: {
- showNotification: false,
- textNotification: '',
- typeNotification: 'warn',
- },
-}
-
-export const fetch = createAsyncThunk('deals/fetch', async (data: any) => {
- const { id, query } = data
- const result = await axios.get(
- `deals${
- query || (id ? `/${id}` : '')
- }`
- )
- return id ? result.data : {rows: result.data.rows, count: result.data.count};
-})
-
-export const deleteItemsByIds = createAsyncThunk(
- 'deals/deleteByIds',
- async (data: any, { rejectWithValue }) => {
- try {
- await axios.post('deals/deleteByIds', { data });
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const deleteItem = createAsyncThunk('deals/deleteDeals', async (id: string, { rejectWithValue }) => {
- try {
- await axios.delete(`deals/${id}`)
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const create = createAsyncThunk('deals/createDeals', async (data: any, { rejectWithValue }) => {
- try {
- const result = await axios.post(
- 'deals',
- { data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const uploadCsv = createAsyncThunk(
- 'deals/uploadCsv',
- async (file: File, { rejectWithValue }) => {
- try {
- const data = new FormData();
- data.append('file', file);
- data.append('filename', file.name);
-
- const result = await axios.post('deals/bulk-import', data, {
- headers: {
- 'Content-Type': 'multipart/form-data',
- },
- });
-
- return result.data;
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const update = createAsyncThunk('deals/updateDeals', async (payload: any, { rejectWithValue }) => {
- try {
- const result = await axios.put(
- `deals/${payload.id}`,
- { id: payload.id, data: payload.data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-
-export const dealsSlice = createSlice({
- name: 'deals',
- initialState,
- reducers: {
- setRefetch: (state, action: PayloadAction) => {
- state.refetch = action.payload;
- },
- },
- extraReducers: (builder) => {
- builder.addCase(fetch.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(fetch.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(fetch.fulfilled, (state, action) => {
- if (action.payload.rows && action.payload.count >= 0) {
- state.deals = action.payload.rows;
- state.count = action.payload.count;
- } else {
- state.deals = action.payload;
- }
- state.loading = false
- })
-
- builder.addCase(deleteItemsByIds.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- });
-
- builder.addCase(deleteItemsByIds.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Deals has been deleted');
- });
-
- builder.addCase(deleteItemsByIds.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- });
-
- builder.addCase(deleteItem.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
-
- builder.addCase(deleteItem.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Deals'.slice(0, -1)} has been deleted`);
- })
-
- builder.addCase(deleteItem.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(create.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Deals'.slice(0, -1)} has been created`);
- })
-
- builder.addCase(update.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(update.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Deals'.slice(0, -1)} has been updated`);
- })
- builder.addCase(update.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(uploadCsv.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- })
- builder.addCase(uploadCsv.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Deals has been uploaded');
- })
- builder.addCase(uploadCsv.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- })
-
-
- },
-})
-
-// Action creators are generated for each case reducer function
- export const { setRefetch } = dealsSlice.actions
-
-export default dealsSlice.reducer
diff --git a/frontend/src/stores/lead_sources/lead_sourcesSlice.ts b/frontend/src/stores/lead_sources/lead_sourcesSlice.ts
deleted file mode 100644
index 9efd68b..0000000
--- a/frontend/src/stores/lead_sources/lead_sourcesSlice.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
-import axios from 'axios'
-import {fulfilledNotify, rejectNotify, resetNotify} from "../../helpers/notifyStateHandler";
-
-interface MainState {
- lead_sources: any
- loading: boolean
- count: number
- refetch: boolean;
- rolesWidgets: any[];
- notify: {
- showNotification: boolean
- textNotification: string
- typeNotification: string
- }
-}
-
-const initialState: MainState = {
- lead_sources: [],
- loading: false,
- count: 0,
- refetch: false,
- rolesWidgets: [],
- notify: {
- showNotification: false,
- textNotification: '',
- typeNotification: 'warn',
- },
-}
-
-export const fetch = createAsyncThunk('lead_sources/fetch', async (data: any) => {
- const { id, query } = data
- const result = await axios.get(
- `lead_sources${
- query || (id ? `/${id}` : '')
- }`
- )
- return id ? result.data : {rows: result.data.rows, count: result.data.count};
-})
-
-export const deleteItemsByIds = createAsyncThunk(
- 'lead_sources/deleteByIds',
- async (data: any, { rejectWithValue }) => {
- try {
- await axios.post('lead_sources/deleteByIds', { data });
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const deleteItem = createAsyncThunk('lead_sources/deleteLead_sources', async (id: string, { rejectWithValue }) => {
- try {
- await axios.delete(`lead_sources/${id}`)
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const create = createAsyncThunk('lead_sources/createLead_sources', async (data: any, { rejectWithValue }) => {
- try {
- const result = await axios.post(
- 'lead_sources',
- { data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const uploadCsv = createAsyncThunk(
- 'lead_sources/uploadCsv',
- async (file: File, { rejectWithValue }) => {
- try {
- const data = new FormData();
- data.append('file', file);
- data.append('filename', file.name);
-
- const result = await axios.post('lead_sources/bulk-import', data, {
- headers: {
- 'Content-Type': 'multipart/form-data',
- },
- });
-
- return result.data;
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const update = createAsyncThunk('lead_sources/updateLead_sources', async (payload: any, { rejectWithValue }) => {
- try {
- const result = await axios.put(
- `lead_sources/${payload.id}`,
- { id: payload.id, data: payload.data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-
-export const lead_sourcesSlice = createSlice({
- name: 'lead_sources',
- initialState,
- reducers: {
- setRefetch: (state, action: PayloadAction) => {
- state.refetch = action.payload;
- },
- },
- extraReducers: (builder) => {
- builder.addCase(fetch.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(fetch.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(fetch.fulfilled, (state, action) => {
- if (action.payload.rows && action.payload.count >= 0) {
- state.lead_sources = action.payload.rows;
- state.count = action.payload.count;
- } else {
- state.lead_sources = action.payload;
- }
- state.loading = false
- })
-
- builder.addCase(deleteItemsByIds.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- });
-
- builder.addCase(deleteItemsByIds.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Lead_sources has been deleted');
- });
-
- builder.addCase(deleteItemsByIds.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- });
-
- builder.addCase(deleteItem.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
-
- builder.addCase(deleteItem.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Lead_sources'.slice(0, -1)} has been deleted`);
- })
-
- builder.addCase(deleteItem.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(create.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Lead_sources'.slice(0, -1)} has been created`);
- })
-
- builder.addCase(update.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(update.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Lead_sources'.slice(0, -1)} has been updated`);
- })
- builder.addCase(update.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(uploadCsv.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- })
- builder.addCase(uploadCsv.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Lead_sources has been uploaded');
- })
- builder.addCase(uploadCsv.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- })
-
-
- },
-})
-
-// Action creators are generated for each case reducer function
- export const { setRefetch } = lead_sourcesSlice.actions
-
-export default lead_sourcesSlice.reducer
diff --git a/frontend/src/stores/leads/leadsSlice.ts b/frontend/src/stores/leads/leadsSlice.ts
deleted file mode 100644
index ee60325..0000000
--- a/frontend/src/stores/leads/leadsSlice.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
-import axios from 'axios'
-import {fulfilledNotify, rejectNotify, resetNotify} from "../../helpers/notifyStateHandler";
-
-interface MainState {
- leads: any
- loading: boolean
- count: number
- refetch: boolean;
- rolesWidgets: any[];
- notify: {
- showNotification: boolean
- textNotification: string
- typeNotification: string
- }
-}
-
-const initialState: MainState = {
- leads: [],
- loading: false,
- count: 0,
- refetch: false,
- rolesWidgets: [],
- notify: {
- showNotification: false,
- textNotification: '',
- typeNotification: 'warn',
- },
-}
-
-export const fetch = createAsyncThunk('leads/fetch', async (data: any) => {
- const { id, query } = data
- const result = await axios.get(
- `leads${
- query || (id ? `/${id}` : '')
- }`
- )
- return id ? result.data : {rows: result.data.rows, count: result.data.count};
-})
-
-export const deleteItemsByIds = createAsyncThunk(
- 'leads/deleteByIds',
- async (data: any, { rejectWithValue }) => {
- try {
- await axios.post('leads/deleteByIds', { data });
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const deleteItem = createAsyncThunk('leads/deleteLeads', async (id: string, { rejectWithValue }) => {
- try {
- await axios.delete(`leads/${id}`)
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const create = createAsyncThunk('leads/createLeads', async (data: any, { rejectWithValue }) => {
- try {
- const result = await axios.post(
- 'leads',
- { data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const uploadCsv = createAsyncThunk(
- 'leads/uploadCsv',
- async (file: File, { rejectWithValue }) => {
- try {
- const data = new FormData();
- data.append('file', file);
- data.append('filename', file.name);
-
- const result = await axios.post('leads/bulk-import', data, {
- headers: {
- 'Content-Type': 'multipart/form-data',
- },
- });
-
- return result.data;
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const update = createAsyncThunk('leads/updateLeads', async (payload: any, { rejectWithValue }) => {
- try {
- const result = await axios.put(
- `leads/${payload.id}`,
- { id: payload.id, data: payload.data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-
-export const leadsSlice = createSlice({
- name: 'leads',
- initialState,
- reducers: {
- setRefetch: (state, action: PayloadAction) => {
- state.refetch = action.payload;
- },
- },
- extraReducers: (builder) => {
- builder.addCase(fetch.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(fetch.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(fetch.fulfilled, (state, action) => {
- if (action.payload.rows && action.payload.count >= 0) {
- state.leads = action.payload.rows;
- state.count = action.payload.count;
- } else {
- state.leads = action.payload;
- }
- state.loading = false
- })
-
- builder.addCase(deleteItemsByIds.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- });
-
- builder.addCase(deleteItemsByIds.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Leads has been deleted');
- });
-
- builder.addCase(deleteItemsByIds.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- });
-
- builder.addCase(deleteItem.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
-
- builder.addCase(deleteItem.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Leads'.slice(0, -1)} has been deleted`);
- })
-
- builder.addCase(deleteItem.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(create.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Leads'.slice(0, -1)} has been created`);
- })
-
- builder.addCase(update.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(update.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Leads'.slice(0, -1)} has been updated`);
- })
- builder.addCase(update.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(uploadCsv.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- })
- builder.addCase(uploadCsv.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Leads has been uploaded');
- })
- builder.addCase(uploadCsv.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- })
-
-
- },
-})
-
-// Action creators are generated for each case reducer function
- export const { setRefetch } = leadsSlice.actions
-
-export default leadsSlice.reducer
diff --git a/frontend/src/stores/pipeline_stages/pipeline_stagesSlice.ts b/frontend/src/stores/pipeline_stages/pipeline_stagesSlice.ts
deleted file mode 100644
index 983048e..0000000
--- a/frontend/src/stores/pipeline_stages/pipeline_stagesSlice.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
-import axios from 'axios'
-import {fulfilledNotify, rejectNotify, resetNotify} from "../../helpers/notifyStateHandler";
-
-interface MainState {
- pipeline_stages: any
- loading: boolean
- count: number
- refetch: boolean;
- rolesWidgets: any[];
- notify: {
- showNotification: boolean
- textNotification: string
- typeNotification: string
- }
-}
-
-const initialState: MainState = {
- pipeline_stages: [],
- loading: false,
- count: 0,
- refetch: false,
- rolesWidgets: [],
- notify: {
- showNotification: false,
- textNotification: '',
- typeNotification: 'warn',
- },
-}
-
-export const fetch = createAsyncThunk('pipeline_stages/fetch', async (data: any) => {
- const { id, query } = data
- const result = await axios.get(
- `pipeline_stages${
- query || (id ? `/${id}` : '')
- }`
- )
- return id ? result.data : {rows: result.data.rows, count: result.data.count};
-})
-
-export const deleteItemsByIds = createAsyncThunk(
- 'pipeline_stages/deleteByIds',
- async (data: any, { rejectWithValue }) => {
- try {
- await axios.post('pipeline_stages/deleteByIds', { data });
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const deleteItem = createAsyncThunk('pipeline_stages/deletePipeline_stages', async (id: string, { rejectWithValue }) => {
- try {
- await axios.delete(`pipeline_stages/${id}`)
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const create = createAsyncThunk('pipeline_stages/createPipeline_stages', async (data: any, { rejectWithValue }) => {
- try {
- const result = await axios.post(
- 'pipeline_stages',
- { data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-export const uploadCsv = createAsyncThunk(
- 'pipeline_stages/uploadCsv',
- async (file: File, { rejectWithValue }) => {
- try {
- const data = new FormData();
- data.append('file', file);
- data.append('filename', file.name);
-
- const result = await axios.post('pipeline_stages/bulk-import', data, {
- headers: {
- 'Content-Type': 'multipart/form-data',
- },
- });
-
- return result.data;
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
- },
-);
-
-export const update = createAsyncThunk('pipeline_stages/updatePipeline_stages', async (payload: any, { rejectWithValue }) => {
- try {
- const result = await axios.put(
- `pipeline_stages/${payload.id}`,
- { id: payload.id, data: payload.data }
- )
- return result.data
- } catch (error) {
- if (!error.response) {
- throw error;
- }
-
- return rejectWithValue(error.response.data);
- }
-})
-
-
-export const pipeline_stagesSlice = createSlice({
- name: 'pipeline_stages',
- initialState,
- reducers: {
- setRefetch: (state, action: PayloadAction) => {
- state.refetch = action.payload;
- },
- },
- extraReducers: (builder) => {
- builder.addCase(fetch.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(fetch.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(fetch.fulfilled, (state, action) => {
- if (action.payload.rows && action.payload.count >= 0) {
- state.pipeline_stages = action.payload.rows;
- state.count = action.payload.count;
- } else {
- state.pipeline_stages = action.payload;
- }
- state.loading = false
- })
-
- builder.addCase(deleteItemsByIds.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- });
-
- builder.addCase(deleteItemsByIds.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Pipeline_stages has been deleted');
- });
-
- builder.addCase(deleteItemsByIds.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- });
-
- builder.addCase(deleteItem.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
-
- builder.addCase(deleteItem.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Pipeline_stages'.slice(0, -1)} has been deleted`);
- })
-
- builder.addCase(deleteItem.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(create.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(create.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Pipeline_stages'.slice(0, -1)} has been created`);
- })
-
- builder.addCase(update.pending, (state) => {
- state.loading = true
- resetNotify(state);
- })
- builder.addCase(update.fulfilled, (state) => {
- state.loading = false
- fulfilledNotify(state, `${'Pipeline_stages'.slice(0, -1)} has been updated`);
- })
- builder.addCase(update.rejected, (state, action) => {
- state.loading = false
- rejectNotify(state, action);
- })
-
- builder.addCase(uploadCsv.pending, (state) => {
- state.loading = true;
- resetNotify(state);
- })
- builder.addCase(uploadCsv.fulfilled, (state) => {
- state.loading = false;
- fulfilledNotify(state, 'Pipeline_stages has been uploaded');
- })
- builder.addCase(uploadCsv.rejected, (state, action) => {
- state.loading = false;
- rejectNotify(state, action);
- })
-
-
- },
-})
-
-// Action creators are generated for each case reducer function
- export const { setRefetch } = pipeline_stagesSlice.actions
-
-export default pipeline_stagesSlice.reducer
diff --git a/frontend/src/stores/store.ts b/frontend/src/stores/store.ts
index 987327c..1113d70 100644
--- a/frontend/src/stores/store.ts
+++ b/frontend/src/stores/store.ts
@@ -7,13 +7,6 @@ import openAiSlice from './openAiSlice';
import usersSlice from "./users/usersSlice";
import rolesSlice from "./roles/rolesSlice";
import permissionsSlice from "./permissions/permissionsSlice";
-import accountsSlice from "./accounts/accountsSlice";
-import contactsSlice from "./contacts/contactsSlice";
-import lead_sourcesSlice from "./lead_sources/lead_sourcesSlice";
-import leadsSlice from "./leads/leadsSlice";
-import pipeline_stagesSlice from "./pipeline_stages/pipeline_stagesSlice";
-import dealsSlice from "./deals/dealsSlice";
-import activitiesSlice from "./activities/activitiesSlice";
export const store = configureStore({
reducer: {
@@ -25,13 +18,6 @@ export const store = configureStore({
users: usersSlice,
roles: rolesSlice,
permissions: permissionsSlice,
-accounts: accountsSlice,
-contacts: contactsSlice,
-lead_sources: lead_sourcesSlice,
-leads: leadsSlice,
-pipeline_stages: pipeline_stagesSlice,
-deals: dealsSlice,
-activities: activitiesSlice,
},
})