diff --git a/.gitignore b/.gitignore index d0eb167..e427ff3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ node_modules/ */node_modules/ */build/ - -**/node_modules/ -**/build/ -.DS_Store -.env \ No newline at end of file diff --git a/app-shell/src/_schema.json b/app-shell/src/_schema.json index ef4183f..1ca9b51 100644 --- a/app-shell/src/_schema.json +++ b/app-shell/src/_schema.json @@ -1,4 +1,5 @@ + + { - "Initial version": "{\"iv\":\"supFIdux6gxPDrZp\",\"encryptedData\":\"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\"}", - "likes": "{\"iv\":\"o8Y4QM9Tx00ZeTJO\",\"encryptedData\":\"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\"}" -} \ No newline at end of file + "Initial version": "{\"iv\":\"supFIdux6gxPDrZp\",\"encryptedData\":\"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\"}" +} diff --git a/backend/src/db/api/likes.js b/backend/src/db/api/likes.js deleted file mode 100644 index 6705688..0000000 --- a/backend/src/db/api/likes.js +++ /dev/null @@ -1,235 +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 LikesDBApi { - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const likes = await db.likes.create( - { - id: data.id || undefined, - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - return likes; - } - - 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 likesData = data.map((item, index) => ({ - id: item.id || undefined, - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const likes = await db.likes.bulkCreate(likesData, { transaction }); - - // For each item created, replace relation files - - return likes; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const likes = await db.likes.findByPk(id, {}, { transaction }); - - const updatePayload = {}; - - updatePayload.updatedById = currentUser.id; - - await likes.update(updatePayload, { transaction }); - - return likes; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const likes = await db.likes.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of likes) { - await record.update({ deletedBy: currentUser.id }, { transaction }); - } - for (const record of likes) { - await record.destroy({ transaction }); - } - }); - - return likes; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const likes = await db.likes.findByPk(id, options); - - await likes.update( - { - deletedBy: currentUser.id, - }, - { - transaction, - }, - ); - - await likes.destroy({ - transaction, - }); - - return likes; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const likes = await db.likes.findOne({ where }, { transaction }); - - if (!likes) { - return likes; - } - - const output = likes.get({ plain: true }); - - 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.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true', - }; - } - - 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.likes.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('likes', 'id', query), - ], - }; - } - - const records = await db.likes.findAll({ - attributes: ['id', 'id'], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['id', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.id, - })); - } -}; diff --git a/backend/src/db/migrations/1744588788792.js b/backend/src/db/migrations/1744588788792.js deleted file mode 100644 index 3ab60dc..0000000 --- a/backend/src/db/migrations/1744588788792.js +++ /dev/null @@ -1,72 +0,0 @@ -module.exports = { - /** - * @param {QueryInterface} queryInterface - * @param {Sequelize} Sequelize - * @returns {Promise} - */ - async up(queryInterface, Sequelize) { - /** - * @type {Transaction} - */ - const transaction = await queryInterface.sequelize.transaction(); - try { - await queryInterface.createTable( - 'likes', - { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { transaction }, - ); - - await transaction.commit(); - } catch (err) { - await transaction.rollback(); - throw err; - } - }, - /** - * @param {QueryInterface} queryInterface - * @param {Sequelize} Sequelize - * @returns {Promise} - */ - async down(queryInterface, Sequelize) { - /** - * @type {Transaction} - */ - const transaction = await queryInterface.sequelize.transaction(); - try { - await queryInterface.dropTable('likes', { transaction }); - - await transaction.commit(); - } catch (err) { - await transaction.rollback(); - throw err; - } - }, -}; diff --git a/backend/src/db/models/likes.js b/backend/src/db/models/likes.js deleted file mode 100644 index 884d1ba..0000000 --- a/backend/src/db/models/likes.js +++ /dev/null @@ -1,45 +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 likes = sequelize.define( - 'likes', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - likes.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.likes.belongsTo(db.users, { - as: 'createdBy', - }); - - db.likes.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - return likes; -}; diff --git a/backend/src/db/seeders/20200430130760-user-roles.js b/backend/src/db/seeders/20200430130760-user-roles.js index 96f97b6..54b0cb5 100644 --- a/backend/src/db/seeders/20200430130760-user-roles.js +++ b/backend/src/db/seeders/20200430130760-user-roles.js @@ -101,7 +101,6 @@ module.exports = { 'students', 'roles', 'permissions', - 'likes', , ]; await queryInterface.bulkInsert( @@ -949,31 +948,6 @@ primary key ("roles_permissionsId", "permissionId") permissionId: getId('DELETE_PERMISSIONS'), }, - { - createdAt, - updatedAt, - roles_permissionsId: getId('Administrator'), - permissionId: getId('CREATE_LIKES'), - }, - { - createdAt, - updatedAt, - roles_permissionsId: getId('Administrator'), - permissionId: getId('READ_LIKES'), - }, - { - createdAt, - updatedAt, - roles_permissionsId: getId('Administrator'), - permissionId: getId('UPDATE_LIKES'), - }, - { - createdAt, - updatedAt, - roles_permissionsId: getId('Administrator'), - permissionId: getId('DELETE_LIKES'), - }, - { createdAt, updatedAt, diff --git a/backend/src/db/seeders/20231127130745-sample-data.js b/backend/src/db/seeders/20231127130745-sample-data.js index 0769ac6..9193cdd 100644 --- a/backend/src/db/seeders/20231127130745-sample-data.js +++ b/backend/src/db/seeders/20231127130745-sample-data.js @@ -13,8 +13,6 @@ const Instructors = db.instructors; const Students = db.students; -const Likes = db.likes; - const AnalyticsData = [ { // type code here for "relation_many" field @@ -33,18 +31,6 @@ const AnalyticsData = [ // type code here for "relation_many" field // type code here for "relation_many" field }, - - { - // type code here for "relation_many" field - // type code here for "relation_many" field - // type code here for "relation_many" field - }, - - { - // type code here for "relation_many" field - // type code here for "relation_many" field - // type code here for "relation_many" field - }, ]; const CoursesData = [ @@ -83,30 +69,6 @@ const CoursesData = [ // type code here for "relation_many" field }, - - { - title: 'Graphic Design', - - description: 'Develop skills in design software and visual communication.', - - // type code here for "relation_many" field - - // type code here for "relation_many" field - - // type code here for "relation_many" field - }, - - { - title: 'Business Management', - - description: 'Understand the fundamentals of managing a business.', - - // type code here for "relation_many" field - - // type code here for "relation_many" field - - // type code here for "relation_many" field - }, ]; const DiscussionBoardsData = [ @@ -127,21 +89,25 @@ const DiscussionBoardsData = [ // type code here for "relation_one" field }, - - { - topic: 'Design Trends', - - // type code here for "relation_one" field - }, - - { - topic: 'Leadership Skills', - - // type code here for "relation_one" field - }, ]; const EnrollmentsData = [ + { + // type code here for "relation_one" field + + // type code here for "relation_one" field + + payment_status: 'paid', + }, + + { + // type code here for "relation_one" field + + // type code here for "relation_one" field + + payment_status: 'paid', + }, + { // type code here for "relation_one" field @@ -149,38 +115,6 @@ const EnrollmentsData = [ payment_status: 'pending', }, - - { - // type code here for "relation_one" field - - // type code here for "relation_one" field - - payment_status: 'overdue', - }, - - { - // type code here for "relation_one" field - - // type code here for "relation_one" field - - payment_status: 'overdue', - }, - - { - // type code here for "relation_one" field - - // type code here for "relation_one" field - - payment_status: 'paid', - }, - - { - // type code here for "relation_one" field - - // type code here for "relation_one" field - - payment_status: 'paid', - }, ]; const InstructorsData = [ @@ -213,26 +147,6 @@ const InstructorsData = [ // type code here for "relation_many" field }, - - { - name: 'Mr. Michael Green', - - email: 'michael.green@example.com', - - qualifications: 'MSc in Mathematics', - - // type code here for "relation_many" field - }, - - { - name: 'Dr. Olivia White', - - email: 'olivia.white@example.com', - - qualifications: 'PhD in Marketing', - - // type code here for "relation_many" field - }, ]; const StudentsData = [ @@ -259,26 +173,8 @@ const StudentsData = [ // type code here for "relation_many" field }, - - { - name: 'Diana Prince', - - email: 'diana.prince@example.com', - - // type code here for "relation_many" field - }, - - { - name: 'Ethan Hunt', - - email: 'ethan.hunt@example.com', - - // type code here for "relation_many" field - }, ]; -const LikesData = [{}, {}, {}, {}, {}]; - // Similar logic for "relation_many" // Similar logic for "relation_many" @@ -326,28 +222,6 @@ async function associateDiscussionBoardWithCourse() { if (DiscussionBoard2?.setCourse) { await DiscussionBoard2.setCourse(relatedCourse2); } - - const relatedCourse3 = await Courses.findOne({ - offset: Math.floor(Math.random() * (await Courses.count())), - }); - const DiscussionBoard3 = await DiscussionBoards.findOne({ - order: [['id', 'ASC']], - offset: 3, - }); - if (DiscussionBoard3?.setCourse) { - await DiscussionBoard3.setCourse(relatedCourse3); - } - - const relatedCourse4 = await Courses.findOne({ - offset: Math.floor(Math.random() * (await Courses.count())), - }); - const DiscussionBoard4 = await DiscussionBoards.findOne({ - order: [['id', 'ASC']], - offset: 4, - }); - if (DiscussionBoard4?.setCourse) { - await DiscussionBoard4.setCourse(relatedCourse4); - } } async function associateEnrollmentWithStudent() { @@ -383,28 +257,6 @@ async function associateEnrollmentWithStudent() { if (Enrollment2?.setStudent) { await Enrollment2.setStudent(relatedStudent2); } - - const relatedStudent3 = await Students.findOne({ - offset: Math.floor(Math.random() * (await Students.count())), - }); - const Enrollment3 = await Enrollments.findOne({ - order: [['id', 'ASC']], - offset: 3, - }); - if (Enrollment3?.setStudent) { - await Enrollment3.setStudent(relatedStudent3); - } - - const relatedStudent4 = await Students.findOne({ - offset: Math.floor(Math.random() * (await Students.count())), - }); - const Enrollment4 = await Enrollments.findOne({ - order: [['id', 'ASC']], - offset: 4, - }); - if (Enrollment4?.setStudent) { - await Enrollment4.setStudent(relatedStudent4); - } } async function associateEnrollmentWithCourse() { @@ -440,28 +292,6 @@ async function associateEnrollmentWithCourse() { if (Enrollment2?.setCourse) { await Enrollment2.setCourse(relatedCourse2); } - - const relatedCourse3 = await Courses.findOne({ - offset: Math.floor(Math.random() * (await Courses.count())), - }); - const Enrollment3 = await Enrollments.findOne({ - order: [['id', 'ASC']], - offset: 3, - }); - if (Enrollment3?.setCourse) { - await Enrollment3.setCourse(relatedCourse3); - } - - const relatedCourse4 = await Courses.findOne({ - offset: Math.floor(Math.random() * (await Courses.count())), - }); - const Enrollment4 = await Enrollments.findOne({ - order: [['id', 'ASC']], - offset: 4, - }); - if (Enrollment4?.setCourse) { - await Enrollment4.setCourse(relatedCourse4); - } } // Similar logic for "relation_many" @@ -482,8 +312,6 @@ module.exports = { await Students.bulkCreate(StudentsData); - await Likes.bulkCreate(LikesData); - await Promise.all([ // Similar logic for "relation_many" @@ -523,7 +351,5 @@ module.exports = { await queryInterface.bulkDelete('instructors', null, {}); await queryInterface.bulkDelete('students', null, {}); - - await queryInterface.bulkDelete('likes', null, {}); }, }; diff --git a/backend/src/db/seeders/20250413235948.js b/backend/src/db/seeders/20250413235948.js deleted file mode 100644 index ddd1a6e..0000000 --- a/backend/src/db/seeders/20250413235948.js +++ /dev/null @@ -1,87 +0,0 @@ -const { v4: uuid } = require('uuid'); -const db = require('../models'); -const Sequelize = require('sequelize'); -const config = require('../../config'); - -module.exports = { - /** - * @param{import("sequelize").QueryInterface} queryInterface - * @return {Promise} - */ - async up(queryInterface) { - const createdAt = new Date(); - const updatedAt = new Date(); - - /** @type {Map} */ - const idMap = new Map(); - - /** - * @param {string} key - * @return {string} - */ - function getId(key) { - if (idMap.has(key)) { - return idMap.get(key); - } - const id = uuid(); - idMap.set(key, id); - return id; - } - - /** - * @param {string} name - */ - function createPermissions(name) { - return [ - { - id: getId(`CREATE_${name.toUpperCase()}`), - createdAt, - updatedAt, - name: `CREATE_${name.toUpperCase()}`, - }, - { - id: getId(`READ_${name.toUpperCase()}`), - createdAt, - updatedAt, - name: `READ_${name.toUpperCase()}`, - }, - { - id: getId(`UPDATE_${name.toUpperCase()}`), - createdAt, - updatedAt, - name: `UPDATE_${name.toUpperCase()}`, - }, - { - id: getId(`DELETE_${name.toUpperCase()}`), - createdAt, - updatedAt, - name: `DELETE_${name.toUpperCase()}`, - }, - ]; - } - - const entities = ['likes']; - - const createdPermissions = entities.flatMap(createPermissions); - - // Add permissions to database - await queryInterface.bulkInsert('permissions', createdPermissions); - // Get permissions ids - const permissionsIds = createdPermissions.map((p) => p.id); - // Get admin role - const adminRole = await db.roles.findOne({ - where: { name: config.roles.admin }, - }); - - if (adminRole) { - // Add permissions to admin role if it exists - await adminRole.addPermissions(permissionsIds); - } - }, - down: async (queryInterface, Sequelize) => { - await queryInterface.bulkDelete( - 'permissions', - entities.flatMap(createPermissions), - ); - }, -}; diff --git a/backend/src/index.js b/backend/src/index.js index 2a90fd2..b0518da 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -37,8 +37,6 @@ const rolesRoutes = require('./routes/roles'); const permissionsRoutes = require('./routes/permissions'); -const likesRoutes = require('./routes/likes'); - const getBaseUrl = (url) => { if (!url) return ''; return url.endsWith('/api') ? url.slice(0, -4) : url; @@ -49,9 +47,9 @@ const options = { openapi: '3.0.0', info: { version: '1.0.0', - title: 'save_schema_test', + title: 'saveschematest', description: - 'save_schema_test Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.', + 'saveschematest Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.', }, servers: [ { @@ -158,12 +156,6 @@ app.use( permissionsRoutes, ); -app.use( - '/api/likes', - passport.authenticate('jwt', { session: false }), - likesRoutes, -); - app.use( '/api/openai', passport.authenticate('jwt', { session: false }), diff --git a/backend/src/routes/likes.js b/backend/src/routes/likes.js deleted file mode 100644 index ed6c9b6..0000000 --- a/backend/src/routes/likes.js +++ /dev/null @@ -1,429 +0,0 @@ -const express = require('express'); - -const LikesService = require('../services/likes'); -const LikesDBApi = require('../db/api/likes'); -const wrapAsync = require('../helpers').wrapAsync; - -const router = express.Router(); - -const { parse } = require('json2csv'); - -const { checkCrudPermissions } = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('likes')); - -/** - * @swagger - * components: - * schemas: - * Likes: - * type: object - * properties: - - */ - -/** - * @swagger - * tags: - * name: Likes - * description: The Likes managing API - */ - -/** - * @swagger - * /api/likes: - * post: - * security: - * - bearerAuth: [] - * tags: [Likes] - * 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/Likes" - * responses: - * 200: - * description: The item was successfully added - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Likes" - * 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 LikesService.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: [Likes] - * 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/Likes" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Likes" - * 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 LikesService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); - }), -); - -/** - * @swagger - * /api/likes/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Likes] - * 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/Likes" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Likes" - * 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 LikesService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); - }), -); - -/** - * @swagger - * /api/likes/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Likes] - * 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/Likes" - * 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 LikesService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); - }), -); - -/** - * @swagger - * /api/likes/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Likes] - * 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/Likes" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post( - '/deleteByIds', - wrapAsync(async (req, res) => { - await LikesService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - }), -); - -/** - * @swagger - * /api/likes: - * get: - * security: - * - bearerAuth: [] - * tags: [Likes] - * summary: Get all likes - * description: Get all likes - * responses: - * 200: - * description: Likes list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Likes" - * 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 LikesDBApi.findAll(req.query, { currentUser }); - if (filetype && filetype === 'csv') { - const fields = ['id']; - 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/likes/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Likes] - * summary: Count all likes - * description: Count all likes - * responses: - * 200: - * description: Likes count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Likes" - * 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 LikesDBApi.findAll(req.query, null, { - countOnly: true, - currentUser, - }); - - res.status(200).send(payload); - }), -); - -/** - * @swagger - * /api/likes/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Likes] - * summary: Find all likes that match search criteria - * description: Find all likes that match search criteria - * responses: - * 200: - * description: Likes list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Likes" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - const payload = await LikesDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/likes/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Likes] - * 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/Likes" - * 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 LikesDBApi.findBy({ id: req.params.id }); - - res.status(200).send(payload); - }), -); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/services/likes.js b/backend/src/services/likes.js deleted file mode 100644 index d8f6f3e..0000000 --- a/backend/src/services/likes.js +++ /dev/null @@ -1,114 +0,0 @@ -const db = require('../db/models'); -const LikesDBApi = require('../db/api/likes'); -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 LikesService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await LikesDBApi.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 LikesDBApi.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 likes = await LikesDBApi.findBy({ id }, { transaction }); - - if (!likes) { - throw new ValidationError('likesNotFound'); - } - - const updatedLikes = await LikesDBApi.update(id, data, { - currentUser, - transaction, - }); - - await transaction.commit(); - return updatedLikes; - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await LikesDBApi.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 LikesDBApi.remove(id, { - currentUser, - transaction, - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } -}; diff --git a/frontend/json/runtimeError.json b/frontend/json/runtimeError.json deleted file mode 100644 index 9e26dfe..0000000 --- a/frontend/json/runtimeError.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/frontend/src/components/Likes/CardLikes.tsx b/frontend/src/components/Likes/CardLikes.tsx deleted file mode 100644 index 92fbddc..0000000 --- a/frontend/src/components/Likes/CardLikes.tsx +++ /dev/null @@ -1,98 +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 = { - likes: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardLikes = ({ - likes, - 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_LIKES'); - - return ( -
- {loading && } -
    - {!loading && - likes.map((item, index) => ( -
  • -
    - - {item.id} - - -
    - -
    -
    -
    -
  • - ))} - {!loading && likes.length === 0 && ( -
    -

    No data to display

    -
    - )} -
-
- -
-
- ); -}; - -export default CardLikes; diff --git a/frontend/src/components/Likes/ListLikes.tsx b/frontend/src/components/Likes/ListLikes.tsx deleted file mode 100644 index 3c31b6b..0000000 --- a/frontend/src/components/Likes/ListLikes.tsx +++ /dev/null @@ -1,85 +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 = { - likes: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListLikes = ({ - likes, - loading, - onDelete, - currentPage, - numPages, - onPageChange, -}: Props) => { - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_LIKES'); - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - return ( - <> -
- {loading && } - {!loading && - likes.map((item) => ( - -
- dark:divide-dark-700 overflow-x-auto' - } - > - -
-
- ))} - {!loading && likes.length === 0 && ( -
-

No data to display

-
- )} -
-
- -
- - ); -}; - -export default ListLikes; diff --git a/frontend/src/components/Likes/TableLikes.tsx b/frontend/src/components/Likes/TableLikes.tsx deleted file mode 100644 index e544926..0000000 --- a/frontend/src/components/Likes/TableLikes.tsx +++ /dev/null @@ -1,481 +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/likes/likesSlice'; -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 './configureLikesCols'; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter'; -import { dataGridStyles } from '../../styles'; - -const perPage = 10; - -const TableSampleLikes = ({ - 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 { - likes, - loading, - count, - notify: likesNotify, - refetch, - } = useAppSelector((state) => state.likes); - 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 (likesNotify.showNotification) { - notify(likesNotify.typeNotification, likesNotify.textNotification); - } - }, [likesNotify.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, `likes`, 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={likes ?? []} - 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} - > -
- <> - {filterItems && - filterItems.map((filterItem) => { - return ( -
-
-
- Filter -
- - {filters.map((selectOption) => ( - - ))} - -
- {filters.find( - (filter) => - filter.title === filterItem?.fields?.selectedField, - )?.type === 'enum' ? ( -
-
Value
- - - {filters - .find( - (filter) => - filter.title === - filterItem?.fields?.selectedField, - ) - ?.options?.map((option) => ( - - ))} - -
- ) : filters.find( - (filter) => - filter.title === - filterItem?.fields?.selectedField, - )?.number ? ( -
-
-
- From -
- -
-
-
- To -
- -
-
- ) : filters.find( - (filter) => - filter.title === - filterItem?.fields?.selectedField, - )?.date ? ( -
-
-
- From -
- -
-
-
- To -
- -
-
- ) : ( -
-
- Contains -
- -
- )} -
-
- Action -
- { - deleteFilter(filterItem.id); - }} - /> -
-
- ); - })} -
- - -
- -
-
-
- ) : null} - -

Are you sure you want to delete this item?

-
- - {dataGrid} - - {selectedRows.length > 0 && - createPortal( - onDeleteRows(selectedRows)} - />, - document.getElementById('delete-rows-button'), - )} - - - ); -}; - -export default TableSampleLikes; diff --git a/frontend/src/components/Likes/configureLikesCols.tsx b/frontend/src/components/Likes/configureLikesCols.tsx deleted file mode 100644 index 1e16b07..0000000 --- a/frontend/src/components/Likes/configureLikesCols.tsx +++ /dev/null @@ -1,61 +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_LIKES'); - - return [ - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - return [ - , - ]; - }, - }, - ]; -}; diff --git a/frontend/src/components/WebPageComponents/Header.tsx b/frontend/src/components/WebPageComponents/Header.tsx index 14ab067..1c882e7 100644 --- a/frontend/src/components/WebPageComponents/Header.tsx +++ b/frontend/src/components/WebPageComponents/Header.tsx @@ -19,7 +19,7 @@ export default function WebSiteHeader({ const websiteHeder = useAppSelector((state) => state.style.websiteHeder); const borders = useAppSelector((state) => state.style.borders); - const style = HeaderStyle.PAGES_LEFT; + const style = HeaderStyle.PAGES_RIGHT; const design = HeaderDesigns.DEFAULT_DESIGN; return ( diff --git a/frontend/src/menuAside.ts b/frontend/src/menuAside.ts index 2fcaa36..3a41f9c 100644 --- a/frontend/src/menuAside.ts +++ b/frontend/src/menuAside.ts @@ -88,20 +88,18 @@ const menuAside: MenuAsideItem[] = [ : icon.mdiTable, permissions: 'READ_PERMISSIONS', }, - { - href: '/likes/likes-list', - label: 'Likes', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: icon.mdiTable ? icon.mdiTable : icon.mdiTable, - permissions: 'READ_LIKES', - }, { href: '/profile', label: 'Profile', icon: icon.mdiAccountCircle, }, + { + href: '/home', + label: 'Home page', + icon: icon.mdiHome, + withDevider: true, + }, { href: '/api-docs', target: '_blank', diff --git a/frontend/src/pages/dashboard.tsx b/frontend/src/pages/dashboard.tsx index 965aaca..25be6e2 100644 --- a/frontend/src/pages/dashboard.tsx +++ b/frontend/src/pages/dashboard.tsx @@ -32,7 +32,6 @@ const Dashboard = () => { const [students, setStudents] = React.useState('Loading...'); const [roles, setRoles] = React.useState('Loading...'); const [permissions, setPermissions] = React.useState('Loading...'); - const [likes, setLikes] = React.useState('Loading...'); const [widgetsRole, setWidgetsRole] = React.useState({ role: { value: '', label: '' }, @@ -53,7 +52,6 @@ const Dashboard = () => { 'students', 'roles', 'permissions', - 'likes', ]; const fns = [ setUsers, @@ -65,7 +63,6 @@ const Dashboard = () => { setStudents, setRoles, setPermissions, - setLikes, ]; const requests = entities.map((entity, index) => { @@ -461,38 +458,6 @@ const Dashboard = () => { )} - - {hasPermission(currentUser, 'READ_LIKES') && ( - -
-
-
-
- Likes -
-
- {likes} -
-
-
- -
-
-
- - )} diff --git a/frontend/src/pages/likes/[likesId].tsx b/frontend/src/pages/likes/[likesId].tsx deleted file mode 100644 index acc8b15..0000000 --- a/frontend/src/pages/likes/[likesId].tsx +++ /dev/null @@ -1,118 +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/likes/likesSlice'; -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 EditLikes = () => { - const router = useRouter(); - const dispatch = useAppDispatch(); - const initVals = {}; - const [initialValues, setInitialValues] = useState(initVals); - - const { likes } = useAppSelector((state) => state.likes); - - const { likesId } = router.query; - - useEffect(() => { - dispatch(fetch({ id: likesId })); - }, [likesId]); - - useEffect(() => { - if (typeof likes === 'object') { - setInitialValues(likes); - } - }, [likes]); - - useEffect(() => { - if (typeof likes === 'object') { - const newInitialVal = { ...initVals }; - - Object.keys(initVals).forEach((el) => (newInitialVal[el] = likes[el])); - - setInitialValues(newInitialVal); - } - }, [likes]); - - const handleSubmit = async (data) => { - await dispatch(update({ id: likesId, data })); - await router.push('/likes/likes-list'); - }; - - return ( - <> - - {getPageTitle('Edit likes')} - - - - {''} - - - handleSubmit(values)} - > -
- - - - - router.push('/likes/likes-list')} - /> - - -
-
-
- - ); -}; - -EditLikes.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ); -}; - -export default EditLikes; diff --git a/frontend/src/pages/likes/likes-edit.tsx b/frontend/src/pages/likes/likes-edit.tsx deleted file mode 100644 index c92db37..0000000 --- a/frontend/src/pages/likes/likes-edit.tsx +++ /dev/null @@ -1,116 +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/likes/likesSlice'; -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 EditLikesPage = () => { - const router = useRouter(); - const dispatch = useAppDispatch(); - const initVals = {}; - const [initialValues, setInitialValues] = useState(initVals); - - const { likes } = useAppSelector((state) => state.likes); - - const { id } = router.query; - - useEffect(() => { - dispatch(fetch({ id: id })); - }, [id]); - - useEffect(() => { - if (typeof likes === 'object') { - setInitialValues(likes); - } - }, [likes]); - - useEffect(() => { - if (typeof likes === 'object') { - const newInitialVal = { ...initVals }; - Object.keys(initVals).forEach((el) => (newInitialVal[el] = likes[el])); - setInitialValues(newInitialVal); - } - }, [likes]); - - const handleSubmit = async (data) => { - await dispatch(update({ id: id, data })); - await router.push('/likes/likes-list'); - }; - - return ( - <> - - {getPageTitle('Edit likes')} - - - - {''} - - - handleSubmit(values)} - > -
- - - - - router.push('/likes/likes-list')} - /> - - -
-
-
- - ); -}; - -EditLikesPage.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ); -}; - -export default EditLikesPage; diff --git a/frontend/src/pages/likes/likes-list.tsx b/frontend/src/pages/likes/likes-list.tsx deleted file mode 100644 index 841dfa7..0000000 --- a/frontend/src/pages/likes/likes-list.tsx +++ /dev/null @@ -1,160 +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 TableLikes from '../../components/Likes/TableLikes'; -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/likes/likesSlice'; - -import { hasPermission } from '../../helpers/userPermissions'; - -const LikesTablesPage = () => { - 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([]); - - const hasCreatePermission = - currentUser && hasPermission(currentUser, 'CREATE_LIKES'); - - const addFilter = () => { - const newItem = { - id: uniqueId(), - fields: { - filterValue: '', - filterValueFrom: '', - filterValueTo: '', - selectedField: '', - }, - }; - newItem.fields.selectedField = filters[0].title; - setFilterItems([...filterItems, newItem]); - }; - - const getLikesCSV = async () => { - const response = await axios({ - url: '/likes?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 = 'likesCSV.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('Likes')} - - - - {''} - - - {hasCreatePermission && ( - - )} - - - - - {hasCreatePermission && ( - setIsModalActive(true)} - /> - )} - -
-
-
-
- - - - -
- - - - - ); -}; - -LikesTablesPage.getLayout = function getLayout(page: ReactElement) { - return ( - {page} - ); -}; - -export default LikesTablesPage; diff --git a/frontend/src/pages/likes/likes-new.tsx b/frontend/src/pages/likes/likes-new.tsx deleted file mode 100644 index ac0fdf4..0000000 --- a/frontend/src/pages/likes/likes-new.tsx +++ /dev/null @@ -1,92 +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/likes/likesSlice'; -import { useAppDispatch } from '../../stores/hooks'; -import { useRouter } from 'next/router'; -import moment from 'moment'; - -const initialValues = {}; - -const LikesNew = () => { - const router = useRouter(); - const dispatch = useAppDispatch(); - - const handleSubmit = async (data) => { - await dispatch(create(data)); - await router.push('/likes/likes-list'); - }; - return ( - <> - - {getPageTitle('New Item')} - - - - {''} - - - handleSubmit(values)} - > -
- - - - - router.push('/likes/likes-list')} - /> - - -
-
-
- - ); -}; - -LikesNew.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ); -}; - -export default LikesNew; diff --git a/frontend/src/pages/likes/likes-table.tsx b/frontend/src/pages/likes/likes-table.tsx deleted file mode 100644 index 9a15606..0000000 --- a/frontend/src/pages/likes/likes-table.tsx +++ /dev/null @@ -1,159 +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 TableLikes from '../../components/Likes/TableLikes'; -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/likes/likesSlice'; - -import { hasPermission } from '../../helpers/userPermissions'; - -const LikesTablesPage = () => { - 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([]); - - const hasCreatePermission = - currentUser && hasPermission(currentUser, 'CREATE_LIKES'); - - const addFilter = () => { - const newItem = { - id: uniqueId(), - fields: { - filterValue: '', - filterValueFrom: '', - filterValueTo: '', - selectedField: '', - }, - }; - newItem.fields.selectedField = filters[0].title; - setFilterItems([...filterItems, newItem]); - }; - - const getLikesCSV = async () => { - const response = await axios({ - url: '/likes?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 = 'likesCSV.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('Likes')} - - - - {''} - - - {hasCreatePermission && ( - - )} - - - - - {hasCreatePermission && ( - setIsModalActive(true)} - /> - )} - -
-
-
-
- - - -
- - - - - ); -}; - -LikesTablesPage.getLayout = function getLayout(page: ReactElement) { - return ( - {page} - ); -}; - -export default LikesTablesPage; diff --git a/frontend/src/pages/likes/likes-view.tsx b/frontend/src/pages/likes/likes-view.tsx deleted file mode 100644 index cdfa75b..0000000 --- a/frontend/src/pages/likes/likes-view.tsx +++ /dev/null @@ -1,76 +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/likes/likesSlice'; -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 LikesView = () => { - const router = useRouter(); - const dispatch = useAppDispatch(); - const { likes } = useAppSelector((state) => state.likes); - - 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 likes')} - - - - - - - - - router.push('/likes/likes-list')} - /> - - - - ); -}; - -LikesView.getLayout = function getLayout(page: ReactElement) { - return ( - {page} - ); -}; - -export default LikesView; diff --git a/frontend/src/stores/likes/likesSlice.ts b/frontend/src/stores/likes/likesSlice.ts deleted file mode 100644 index aadbd82..0000000 --- a/frontend/src/stores/likes/likesSlice.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; -import axios from 'axios'; -import { - fulfilledNotify, - rejectNotify, - resetNotify, -} from '../../helpers/notifyStateHandler'; - -interface MainState { - likes: any; - loading: boolean; - count: number; - refetch: boolean; - rolesWidgets: any[]; - notify: { - showNotification: boolean; - textNotification: string; - typeNotification: string; - }; -} - -const initialState: MainState = { - likes: [], - loading: false, - count: 0, - refetch: false, - rolesWidgets: [], - notify: { - showNotification: false, - textNotification: '', - typeNotification: 'warn', - }, -}; - -export const fetch = createAsyncThunk('likes/fetch', async (data: any) => { - const { id, query } = data; - const result = await axios.get(`likes${query || (id ? `/${id}` : '')}`); - return id - ? result.data - : { rows: result.data.rows, count: result.data.count }; -}); - -export const deleteItemsByIds = createAsyncThunk( - 'likes/deleteByIds', - async (data: any, { rejectWithValue }) => { - try { - await axios.post('likes/deleteByIds', { data }); - } catch (error) { - if (!error.response) { - throw error; - } - - return rejectWithValue(error.response.data); - } - }, -); - -export const deleteItem = createAsyncThunk( - 'likes/deleteLikes', - async (id: string, { rejectWithValue }) => { - try { - await axios.delete(`likes/${id}`); - } catch (error) { - if (!error.response) { - throw error; - } - - return rejectWithValue(error.response.data); - } - }, -); - -export const create = createAsyncThunk( - 'likes/createLikes', - async (data: any, { rejectWithValue }) => { - try { - const result = await axios.post('likes', { data }); - return result.data; - } catch (error) { - if (!error.response) { - throw error; - } - - return rejectWithValue(error.response.data); - } - }, -); - -export const uploadCsv = createAsyncThunk( - 'likes/uploadCsv', - async (file: File, { rejectWithValue }) => { - try { - const data = new FormData(); - data.append('file', file); - data.append('filename', file.name); - - const result = await axios.post('likes/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( - 'likes/updateLikes', - async (payload: any, { rejectWithValue }) => { - try { - const result = await axios.put(`likes/${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 likesSlice = createSlice({ - name: 'likes', - 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.likes = action.payload.rows; - state.count = action.payload.count; - } else { - state.likes = 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, 'Likes 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, `${'Likes'.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, `${'Likes'.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, `${'Likes'.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, 'Likes 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 } = likesSlice.actions; - -export default likesSlice.reducer; diff --git a/frontend/src/stores/store.ts b/frontend/src/stores/store.ts index 3a71946..aaf78cc 100644 --- a/frontend/src/stores/store.ts +++ b/frontend/src/stores/store.ts @@ -13,7 +13,6 @@ import instructorsSlice from './instructors/instructorsSlice'; import studentsSlice from './students/studentsSlice'; import rolesSlice from './roles/rolesSlice'; import permissionsSlice from './permissions/permissionsSlice'; -import likesSlice from './likes/likesSlice'; export const store = configureStore({ reducer: { @@ -31,7 +30,6 @@ export const store = configureStore({ students: studentsSlice, roles: rolesSlice, permissions: permissionsSlice, - likes: likesSlice, }, });