Initial commit - Rentall App
- Full-stack rental marketplace application - React frontend with TypeScript - Node.js/Express backend with JWT authentication - Features: item listings, rental requests, calendar availability, user profiles
This commit is contained in:
110
backend/models/Item.js
Normal file
110
backend/models/Item.js
Normal file
@@ -0,0 +1,110 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
|
||||
const Item = sequelize.define('Item', {
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
primaryKey: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false
|
||||
},
|
||||
tags: {
|
||||
type: DataTypes.ARRAY(DataTypes.STRING),
|
||||
defaultValue: []
|
||||
},
|
||||
pickUpAvailable: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false
|
||||
},
|
||||
localDeliveryAvailable: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false
|
||||
},
|
||||
localDeliveryRadius: {
|
||||
type: DataTypes.INTEGER,
|
||||
validate: {
|
||||
min: 1,
|
||||
max: 100
|
||||
}
|
||||
},
|
||||
shippingAvailable: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false
|
||||
},
|
||||
inPlaceUseAvailable: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false
|
||||
},
|
||||
pricePerHour: {
|
||||
type: DataTypes.DECIMAL(10, 2)
|
||||
},
|
||||
pricePerDay: {
|
||||
type: DataTypes.DECIMAL(10, 2)
|
||||
},
|
||||
replacementCost: {
|
||||
type: DataTypes.DECIMAL(10, 2),
|
||||
allowNull: false
|
||||
},
|
||||
location: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
latitude: {
|
||||
type: DataTypes.DECIMAL(10, 8)
|
||||
},
|
||||
longitude: {
|
||||
type: DataTypes.DECIMAL(11, 8)
|
||||
},
|
||||
images: {
|
||||
type: DataTypes.ARRAY(DataTypes.STRING),
|
||||
defaultValue: []
|
||||
},
|
||||
availability: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true
|
||||
},
|
||||
specifications: {
|
||||
type: DataTypes.JSONB,
|
||||
defaultValue: {}
|
||||
},
|
||||
rules: {
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
minimumRentalDays: {
|
||||
type: DataTypes.INTEGER,
|
||||
defaultValue: 1
|
||||
},
|
||||
maximumRentalDays: {
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
needsTraining: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false
|
||||
},
|
||||
unavailablePeriods: {
|
||||
type: DataTypes.JSONB,
|
||||
defaultValue: []
|
||||
},
|
||||
ownerId: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: 'Users',
|
||||
key: 'id'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Item;
|
||||
76
backend/models/Rental.js
Normal file
76
backend/models/Rental.js
Normal file
@@ -0,0 +1,76 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
|
||||
const Rental = sequelize.define('Rental', {
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
primaryKey: true
|
||||
},
|
||||
itemId: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: 'Items',
|
||||
key: 'id'
|
||||
}
|
||||
},
|
||||
renterId: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: 'Users',
|
||||
key: 'id'
|
||||
}
|
||||
},
|
||||
ownerId: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: 'Users',
|
||||
key: 'id'
|
||||
}
|
||||
},
|
||||
startDate: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
},
|
||||
endDate: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
},
|
||||
totalAmount: {
|
||||
type: DataTypes.DECIMAL(10, 2),
|
||||
allowNull: false
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.ENUM('pending', 'confirmed', 'active', 'completed', 'cancelled'),
|
||||
defaultValue: 'pending'
|
||||
},
|
||||
paymentStatus: {
|
||||
type: DataTypes.ENUM('pending', 'paid', 'refunded'),
|
||||
defaultValue: 'pending'
|
||||
},
|
||||
deliveryMethod: {
|
||||
type: DataTypes.ENUM('pickup', 'delivery'),
|
||||
defaultValue: 'pickup'
|
||||
},
|
||||
deliveryAddress: {
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
notes: {
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
rating: {
|
||||
type: DataTypes.INTEGER,
|
||||
validate: {
|
||||
min: 1,
|
||||
max: 5
|
||||
}
|
||||
},
|
||||
review: {
|
||||
type: DataTypes.TEXT
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Rental;
|
||||
66
backend/models/User.js
Normal file
66
backend/models/User.js
Normal file
@@ -0,0 +1,66 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
const User = sequelize.define('User', {
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
primaryKey: true
|
||||
},
|
||||
username: {
|
||||
type: DataTypes.STRING,
|
||||
unique: true,
|
||||
allowNull: false
|
||||
},
|
||||
email: {
|
||||
type: DataTypes.STRING,
|
||||
unique: true,
|
||||
allowNull: false,
|
||||
validate: {
|
||||
isEmail: true
|
||||
}
|
||||
},
|
||||
password: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
firstName: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
lastName: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
phone: {
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
address: {
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
profileImage: {
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
isVerified: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false
|
||||
}
|
||||
}, {
|
||||
hooks: {
|
||||
beforeCreate: async (user) => {
|
||||
user.password = await bcrypt.hash(user.password, 10);
|
||||
},
|
||||
beforeUpdate: async (user) => {
|
||||
if (user.changed('password')) {
|
||||
user.password = await bcrypt.hash(user.password, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
User.prototype.comparePassword = async function(password) {
|
||||
return bcrypt.compare(password, this.password);
|
||||
};
|
||||
|
||||
module.exports = User;
|
||||
22
backend/models/index.js
Normal file
22
backend/models/index.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const sequelize = require('../config/database');
|
||||
const User = require('./User');
|
||||
const Item = require('./Item');
|
||||
const Rental = require('./Rental');
|
||||
|
||||
User.hasMany(Item, { as: 'ownedItems', foreignKey: 'ownerId' });
|
||||
Item.belongsTo(User, { as: 'owner', foreignKey: 'ownerId' });
|
||||
|
||||
User.hasMany(Rental, { as: 'rentalsAsRenter', foreignKey: 'renterId' });
|
||||
User.hasMany(Rental, { as: 'rentalsAsOwner', foreignKey: 'ownerId' });
|
||||
|
||||
Item.hasMany(Rental, { as: 'rentals', foreignKey: 'itemId' });
|
||||
Rental.belongsTo(Item, { as: 'item', foreignKey: 'itemId' });
|
||||
Rental.belongsTo(User, { as: 'renter', foreignKey: 'renterId' });
|
||||
Rental.belongsTo(User, { as: 'owner', foreignKey: 'ownerId' });
|
||||
|
||||
module.exports = {
|
||||
sequelize,
|
||||
User,
|
||||
Item,
|
||||
Rental
|
||||
};
|
||||
Reference in New Issue
Block a user