streamlined address and availability

This commit is contained in:
jackiettran
2025-08-20 14:56:16 -04:00
parent 66dc187295
commit ddd27a59f9
10 changed files with 1173 additions and 314 deletions

View File

@@ -74,6 +74,30 @@ const User = sequelize.define('User', {
isVerified: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
defaultAvailableAfter: {
type: DataTypes.STRING,
defaultValue: '09:00'
},
defaultAvailableBefore: {
type: DataTypes.STRING,
defaultValue: '17:00'
},
defaultSpecifyTimesPerDay: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
defaultWeeklyTimes: {
type: DataTypes.JSONB,
defaultValue: {
sunday: { availableAfter: "09:00", availableBefore: "17:00" },
monday: { availableAfter: "09:00", availableBefore: "17:00" },
tuesday: { availableAfter: "09:00", availableBefore: "17:00" },
wednesday: { availableAfter: "09:00", availableBefore: "17:00" },
thursday: { availableAfter: "09:00", availableBefore: "17:00" },
friday: { availableAfter: "09:00", availableBefore: "17:00" },
saturday: { availableAfter: "09:00", availableBefore: "17:00" }
}
}
}, {
hooks: {

View File

@@ -0,0 +1,54 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const UserAddress = sequelize.define('UserAddress', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
},
userId: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'Users',
key: 'id'
}
},
address1: {
type: DataTypes.STRING,
allowNull: false
},
address2: {
type: DataTypes.STRING
},
city: {
type: DataTypes.STRING,
allowNull: false
},
state: {
type: DataTypes.STRING,
allowNull: false
},
zipCode: {
type: DataTypes.STRING,
allowNull: false
},
country: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 'US'
},
latitude: {
type: DataTypes.DECIMAL(10, 8)
},
longitude: {
type: DataTypes.DECIMAL(11, 8)
},
isPrimary: {
type: DataTypes.BOOLEAN,
defaultValue: false
}
});
module.exports = UserAddress;

View File

@@ -5,6 +5,7 @@ const Rental = require('./Rental');
const Message = require('./Message');
const ItemRequest = require('./ItemRequest');
const ItemRequestResponse = require('./ItemRequestResponse');
const UserAddress = require('./UserAddress');
User.hasMany(Item, { as: 'ownedItems', foreignKey: 'ownerId' });
Item.belongsTo(User, { as: 'owner', foreignKey: 'ownerId' });
@@ -33,6 +34,9 @@ ItemRequestResponse.belongsTo(User, { as: 'responder', foreignKey: 'responderId'
ItemRequestResponse.belongsTo(ItemRequest, { as: 'itemRequest', foreignKey: 'itemRequestId' });
ItemRequestResponse.belongsTo(Item, { as: 'existingItem', foreignKey: 'existingItemId' });
User.hasMany(UserAddress, { as: 'addresses', foreignKey: 'userId' });
UserAddress.belongsTo(User, { as: 'user', foreignKey: 'userId' });
module.exports = {
sequelize,
User,
@@ -40,5 +44,6 @@ module.exports = {
Rental,
Message,
ItemRequest,
ItemRequestResponse
ItemRequestResponse,
UserAddress
};

View File

@@ -1,5 +1,5 @@
const express = require('express');
const { User } = require('../models'); // Import from models/index.js to get models with associations
const { User, UserAddress } = require('../models'); // Import from models/index.js to get models with associations
const { authenticateToken } = require('../middleware/auth');
const { uploadProfileImage } = require('../middleware/upload');
const fs = require('fs').promises;
@@ -17,6 +17,105 @@ router.get('/profile', authenticateToken, async (req, res) => {
}
});
// Address routes (must come before /:id route)
router.get('/addresses', authenticateToken, async (req, res) => {
try {
const addresses = await UserAddress.findAll({
where: { userId: req.user.id },
order: [['isPrimary', 'DESC'], ['createdAt', 'ASC']]
});
res.json(addresses);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
router.post('/addresses', authenticateToken, async (req, res) => {
try {
const address = await UserAddress.create({
...req.body,
userId: req.user.id
});
res.status(201).json(address);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
router.put('/addresses/:id', authenticateToken, async (req, res) => {
try {
const address = await UserAddress.findByPk(req.params.id);
if (!address) {
return res.status(404).json({ error: 'Address not found' });
}
if (address.userId !== req.user.id) {
return res.status(403).json({ error: 'Unauthorized' });
}
await address.update(req.body);
res.json(address);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
router.delete('/addresses/:id', authenticateToken, async (req, res) => {
try {
const address = await UserAddress.findByPk(req.params.id);
if (!address) {
return res.status(404).json({ error: 'Address not found' });
}
if (address.userId !== req.user.id) {
return res.status(403).json({ error: 'Unauthorized' });
}
await address.destroy();
res.status(204).send();
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// User availability routes (must come before /:id route)
router.get('/availability', authenticateToken, async (req, res) => {
try {
const user = await User.findByPk(req.user.id, {
attributes: ['defaultAvailableAfter', 'defaultAvailableBefore', 'defaultSpecifyTimesPerDay', 'defaultWeeklyTimes']
});
res.json({
generalAvailableAfter: user.defaultAvailableAfter,
generalAvailableBefore: user.defaultAvailableBefore,
specifyTimesPerDay: user.defaultSpecifyTimesPerDay,
weeklyTimes: user.defaultWeeklyTimes
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
router.put('/availability', authenticateToken, async (req, res) => {
try {
const { generalAvailableAfter, generalAvailableBefore, specifyTimesPerDay, weeklyTimes } = req.body;
await User.update({
defaultAvailableAfter: generalAvailableAfter,
defaultAvailableBefore: generalAvailableBefore,
defaultSpecifyTimesPerDay: specifyTimesPerDay,
defaultWeeklyTimes: weeklyTimes
}, {
where: { id: req.user.id }
});
res.json({ message: 'Availability updated successfully' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
router.get('/:id', async (req, res) => {
try {
const user = await User.findByPk(req.params.id, {