diff --git a/backend/src/db/migrations/1780000000000.js b/backend/src/db/migrations/1780000000000.js
new file mode 100644
index 0000000..a3c0b2c
--- /dev/null
+++ b/backend/src/db/migrations/1780000000000.js
@@ -0,0 +1,47 @@
+module.exports = {
+ async up(queryInterface, Sequelize) {
+ try {
+ // 1. Users
+ await queryInterface.addColumn('users', 'role', { type: Sequelize.DataTypes.ENUM('Student_Freelancer', 'Client', 'Admin') }).catch(console.error);
+ await queryInterface.addColumn('users', 'name', { type: Sequelize.DataTypes.STRING }).catch(console.error);
+ await queryInterface.addColumn('users', 'is_verified_student', { type: Sequelize.DataTypes.BOOLEAN, defaultValue: false }).catch(console.error);
+ await queryInterface.addColumn('users', 'wallet_balance', { type: Sequelize.DataTypes.DECIMAL, defaultValue: 0.0 }).catch(console.error);
+ await queryInterface.addColumn('users', 'skills', { type: Sequelize.DataTypes.ARRAY(Sequelize.DataTypes.STRING) }).catch(console.error);
+ await queryInterface.addColumn('users', 'rating', { type: Sequelize.DataTypes.DECIMAL, defaultValue: 0.0 }).catch(console.error);
+
+ // 2. Jobs
+ await queryInterface.addColumn('jobs', 'budget', { type: Sequelize.DataTypes.DECIMAL }).catch(console.error);
+ await queryInterface.removeColumn('jobs', 'status').catch(console.error);
+ await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_jobs_status" CASCADE;').catch(console.error);
+ await queryInterface.addColumn('jobs', 'status', { type: Sequelize.DataTypes.ENUM('Open', 'In-Progress', 'Under_Review', 'Completed', 'Disputed') }).catch(console.error);
+
+ // 3. Proposals
+ await queryInterface.renameColumn('proposals', 'proposed_amount', 'bid_amount').catch(console.error);
+ await queryInterface.removeColumn('proposals', 'status').catch(console.error);
+ await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_proposals_status" CASCADE;').catch(console.error);
+ await queryInterface.addColumn('proposals', 'status', { type: Sequelize.DataTypes.ENUM('Pending', 'Accepted', 'Rejected') }).catch(console.error);
+
+ // 4. Escrow Transactions
+ await queryInterface.createTable('escrow_transactions', {
+ id: { type: Sequelize.DataTypes.UUID, defaultValue: Sequelize.DataTypes.UUIDV4, primaryKey: true },
+ jobId: { type: Sequelize.DataTypes.UUID, references: { model: 'jobs', key: 'id' } },
+ clientId: { type: Sequelize.DataTypes.UUID, references: { model: 'users', key: 'id' } },
+ freelancerId: { type: Sequelize.DataTypes.UUID, references: { model: 'users', key: 'id' } },
+ total_amount: { type: Sequelize.DataTypes.DECIMAL },
+ client_fee: { type: Sequelize.DataTypes.DECIMAL },
+ freelancer_fee: { type: Sequelize.DataTypes.DECIMAL },
+ status: { type: Sequelize.DataTypes.ENUM('Held_in_Escrow', 'Released_to_Freelancer', 'Refunded') },
+ importHash: { type: Sequelize.DataTypes.STRING(255), allowNull: true, unique: true },
+ createdAt: { type: Sequelize.DataTypes.DATE, allowNull: false },
+ updatedAt: { type: Sequelize.DataTypes.DATE, allowNull: false },
+ deletedAt: { type: Sequelize.DataTypes.DATE }
+ }).catch(console.error);
+
+ } catch (err) {
+ console.error(err);
+ }
+ },
+
+ async down() {
+ }
+};
\ No newline at end of file
diff --git a/backend/src/db/models/escrow_transactions.js b/backend/src/db/models/escrow_transactions.js
new file mode 100644
index 0000000..3383fc3
--- /dev/null
+++ b/backend/src/db/models/escrow_transactions.js
@@ -0,0 +1,77 @@
+
+
+module.exports = function(sequelize, DataTypes) {
+ const escrow_transactions = sequelize.define(
+ 'escrow_transactions',
+ {
+ id: {
+ type: DataTypes.UUID,
+ defaultValue: DataTypes.UUIDV4,
+ primaryKey: true,
+ },
+ total_amount: {
+ type: DataTypes.DECIMAL,
+ },
+ client_fee: {
+ type: DataTypes.DECIMAL,
+ },
+ freelancer_fee: {
+ type: DataTypes.DECIMAL,
+ },
+ status: {
+ type: DataTypes.ENUM,
+ values: [
+ "Held_in_Escrow",
+ "Released_to_Freelancer",
+ "Refunded"
+ ],
+ },
+ importHash: {
+ type: DataTypes.STRING(255),
+ allowNull: true,
+ unique: true,
+ },
+ },
+ {
+ timestamps: true,
+ paranoid: true,
+ freezeTableName: true,
+ },
+ );
+
+ escrow_transactions.associate = (db) => {
+ db.escrow_transactions.belongsTo(db.jobs, {
+ as: 'job',
+ foreignKey: {
+ name: 'jobId',
+ },
+ constraints: false,
+ });
+
+ db.escrow_transactions.belongsTo(db.users, {
+ as: 'client',
+ foreignKey: {
+ name: 'clientId',
+ },
+ constraints: false,
+ });
+
+ db.escrow_transactions.belongsTo(db.users, {
+ as: 'freelancer',
+ foreignKey: {
+ name: 'freelancerId',
+ },
+ constraints: false,
+ });
+
+ db.escrow_transactions.belongsTo(db.users, {
+ as: 'createdBy',
+ });
+
+ db.escrow_transactions.belongsTo(db.users, {
+ as: 'updatedBy',
+ });
+ };
+
+ return escrow_transactions;
+};
\ No newline at end of file
diff --git a/backend/src/db/models/jobs.js b/backend/src/db/models/jobs.js
index 771b086..4f51d3b 100644
--- a/backend/src/db/models/jobs.js
+++ b/backend/src/db/models/jobs.js
@@ -28,7 +28,7 @@ description: {
},
-budget_min: {
+budget: { type: DataTypes.DECIMAL }, budget_min: {
type: DataTypes.DECIMAL,
@@ -79,22 +79,21 @@ status: {
values: [
-"draft",
+"Open",
-"open",
+"In-Progress",
-"in_progress",
+"Under_Review",
-"in_review",
+"Completed",
-"completed",
+"Disputed",
-"cancelled"
],
diff --git a/backend/src/db/models/proposals.js b/backend/src/db/models/proposals.js
index b1dc234..cca54ef 100644
--- a/backend/src/db/models/proposals.js
+++ b/backend/src/db/models/proposals.js
@@ -21,7 +21,7 @@ cover_letter: {
},
-proposed_amount: {
+bid_amount: {
type: DataTypes.DECIMAL,
@@ -58,19 +58,17 @@ status: {
values: [
-"submitted",
+"Pending",
+"Accepted",
+"Rejected"
-"shortlisted",
-"accepted",
-"rejected",
-"withdrawn"
],
diff --git a/backend/src/db/models/users.js b/backend/src/db/models/users.js
index ac0dcf8..3c3db49 100644
--- a/backend/src/db/models/users.js
+++ b/backend/src/db/models/users.js
@@ -14,7 +14,7 @@ module.exports = function(sequelize, DataTypes) {
primaryKey: true,
},
-firstName: {
+role: { type: DataTypes.ENUM, values: ["Student_Freelancer", "Client", "Admin"] }, name: { type: DataTypes.STRING }, is_verified_student: { type: DataTypes.BOOLEAN, defaultValue: false }, wallet_balance: { type: DataTypes.DECIMAL, defaultValue: 0.0 }, skills: { type: DataTypes.ARRAY(DataTypes.STRING) }, rating: { type: DataTypes.DECIMAL, defaultValue: 0.0 }, firstName: {
type: DataTypes.TEXT,
diff --git a/backend/src/db/seeders/20200430130760-user-roles.js b/backend/src/db/seeders/20200430130760-user-roles.js
index 978db65..414e9b9 100644
--- a/backend/src/db/seeders/20200430130760-user-roles.js
+++ b/backend/src/db/seeders/20200430130760-user-roles.js
@@ -2492,6 +2492,8 @@ await queryInterface.bulkInsert("rolesPermissionsPermissions", [
{ createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_API_DOCS') },
{ createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_SEARCH') },
+ { createdAt, updatedAt, roles_permissionsId: getId("Public"), permissionId: getId('READ_SERVICE_LISTINGS') },
+ { createdAt, updatedAt, roles_permissionsId: getId("Public"), permissionId: getId('READ_SERVICE_CATEGORIES') },
]);
diff --git a/backend/src/index.js b/backend/src/index.js
index f5be12e..8547a18 100644
--- a/backend/src/index.js
+++ b/backend/src/index.js
@@ -137,9 +137,9 @@ app.use('/api/permissions', passport.authenticate('jwt', {session: false}), perm
app.use('/api/skills', passport.authenticate('jwt', {session: false}), skillsRoutes);
-app.use('/api/service_categories', passport.authenticate('jwt', {session: false}), service_categoriesRoutes);
+app.use('/api/service_categories', service_categoriesRoutes);
-app.use('/api/service_listings', passport.authenticate('jwt', {session: false}), service_listingsRoutes);
+app.use('/api/service_listings', service_listingsRoutes);
app.use('/api/tags', passport.authenticate('jwt', {session: false}), tagsRoutes);
diff --git a/frontend/src/components/AsideMenuLayer.tsx b/frontend/src/components/AsideMenuLayer.tsx
index af59df8..9f8fc3b 100644
--- a/frontend/src/components/AsideMenuLayer.tsx
+++ b/frontend/src/components/AsideMenuLayer.tsx
@@ -1,10 +1,10 @@
import React from 'react'
-import { mdiLogout, mdiClose } from '@mdi/js'
+import { mdiClose } from '@mdi/js'
import BaseIcon from './BaseIcon'
import AsideMenuList from './AsideMenuList'
import { MenuAsideItem } from '../interfaces'
import { useAppSelector } from '../stores/hooks'
-import Link from 'next/link';
+import Logo from './Logo'
type Props = {
@@ -37,11 +37,8 @@ export default function AsideMenuLayer({ menu, className = '', ...props }: Props
-
-
-
FreelanceFusion MVP
-
-
+
+