From b56f2a0593b0ccc624a292303668a8045ee74d81 Mon Sep 17 00:00:00 2001 From: singharaj usai Date: Fri, 18 Oct 2024 19:13:33 -0400 Subject: [PATCH] wearing shirts now works --- client/html/pages/catalog/catalog.html | 2 +- client/js/avatar.js | 181 ++++++++++++++++++------- client/js/user-profile.js | 12 +- server/functions/api/routes/avatar.js | 70 +++++++--- server/functions/api/routes/shirt.js | 5 +- 5 files changed, 197 insertions(+), 73 deletions(-) diff --git a/client/html/pages/catalog/catalog.html b/client/html/pages/catalog/catalog.html index 535ad9e..765c638 100644 --- a/client/html/pages/catalog/catalog.html +++ b/client/html/pages/catalog/catalog.html @@ -50,7 +50,7 @@
diff --git a/client/js/avatar.js b/client/js/avatar.js index de7a390..6cb8392 100644 --- a/client/js/avatar.js +++ b/client/js/avatar.js @@ -19,7 +19,6 @@ function loadAvatarsItems() { let currentPage = 1; let totalPages = 1; - function loadShirts(page = 1) { const token = localStorage.getItem('token'); console.log('Loading shirts for user, page:', page); @@ -31,7 +30,7 @@ function loadShirts(page = 1) { Authorization: `Bearer ${token}`, }, success: function (res) { - console.log('Shirts loaded successfully:', res.shirts.length); + console.log('Shirts loaded successfully:', res.shirts); displayUserShirts(res.shirts); updatePagination(res.currentPage, res.totalPages); totalPages = res.totalPages; @@ -55,9 +54,21 @@ function displayUserShirts(shirts) { return; } + // Get the user ID from local storage + const token = localStorage.getItem('token'); + let currentUserId = null; + if (token) { + try { + const payload = JSON.parse(atob(token.split('.')[1])); + currentUserId = payload.userId; + } catch (error) { + console.error('Error decoding token:', error); + } + } + console.log('Displaying shirts:', shirts.length); shirts.forEach((shirt) => { - if (!shirt || !shirt.Name || !shirt.ThumbnailLocation) { + if (!shirt || !shirt.Name || !shirt.FileLocation) { console.error('Invalid shirt object:', shirt); return; } @@ -65,16 +76,16 @@ function displayUserShirts(shirts) { shirt.Name, shirt.ThumbnailLocation, shirt.creator ? shirt.creator.username : 'Unknown', - shirt.Price, shirt._id, - 'shirt' + 'shirt', + shirt.creator && shirt.creator._id === currentUserId ? 'Created' : 'Owned' + ); container.append(shirtHtml); }); } - function updatePagination(currentPage, totalPages) { const paginationContainer = $('#pagination-container'); paginationContainer.empty(); @@ -134,7 +145,7 @@ function Pagination() { }); } -function generateItemHtml(name, imageSrc, creator, id, type) { +function generateItemHtml(name, imageSrc, creator, id, type, ownership) { return `
@@ -144,6 +155,7 @@ function generateItemHtml(name, imageSrc, creator, id, type) {

${name}

Creator: ${creator}

+

Status: ${ownership}

@@ -152,47 +164,65 @@ function generateItemHtml(name, imageSrc, creator, id, type) { } function setupItemSelection() { - $(document).on('click', '.select-item', function () { + $(document).on('click', '.wear-item', function () { const type = $(this).data('type'); const itemId = $(this).data('id'); - wearItem(type, itemId); - saveAvatarSelection(type, itemId); + const isWearing = $(this).hasClass('btn-success'); + + if (isWearing) { + removeItem(type); + } else { + wearItem(type, itemId); + } + }); + + $(document).on('click', '.remove-item', function () { + const type = $(this).data('type'); + removeItem(type); }); } function wearItem(type, itemId) { const token = localStorage.getItem('token'); - let apiUrl = ''; - switch (type) { - case 'shirt': - apiUrl = `/api/shirts/${itemId}`; - break; - // Add cases for 'pants' and 'hat' when made - default: - return; - } + console.log(`Attempting to wear ${type} with ID: ${itemId}`); $.ajax({ - url: apiUrl, - method: 'GET', + url: '/api/avatar', + method: 'PUT', headers: { Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', }, - success: function (item) { - updateAvatarDisplay(type, item.thumbnailUrl); // item.ThumbnailLocation - updateCurrentlyWearing(type, item); + data: JSON.stringify({ type, itemId }), + success: function (response) { + console.log('Avatar updated successfully:', response); + updateAvatarDisplay(type, response.avatar[type]); + updateCurrentlyWearing(type, response.avatar[type]); + updateWearButton(type, itemId, true); + showAlert('success', `Wore your ${type} successfully.`); }, error: function (xhr, status, error) { - console.error(`Error fetching ${type}:`, error); + console.error(`Error wearing ${type}:`, error); + console.error('Status:', status); + console.error('Response:', xhr.responseText); + let errorMessage = `Error wearing ${type}. Please try again later.`; + if (xhr.responseJSON && xhr.responseJSON.error) { + errorMessage = xhr.responseJSON.error; + } + showAlert('danger', errorMessage); }, }); } -function updateAvatarDisplay(type, imageUrl) { +function updateAvatarDisplay(type, item) { switch (type) { case 'shirt': - $('#avatar-shirt').attr('src', imageUrl); + if (item && item.ThumbnailLocation) { + $('#avatar-shirt').attr('src', item.ThumbnailLocation); + } else { + $('#avatar-shirt').attr('src', ''); + } break; // Add cases for 'pants' and 'hat' when i makethem default: @@ -203,19 +233,18 @@ function updateAvatarDisplay(type, imageUrl) { function updateCurrentlyWearing(type, item) { const container = $('#currently-wearing'); - const existingItem = container.find(`[data-type="${type}"]`); - - if (existingItem.length) { - existingItem.remove(); - } + container.find(`[data-type="${type}"]`).remove(); const itemHtml = ` -
-
- ${item.Name} -
-
${item.Name}
- +
+
+
+

${type.charAt(0).toUpperCase() + type.slice(1)}

+
+
+ ${item.Name} +
${item.Name}
+
@@ -224,6 +253,40 @@ function updateCurrentlyWearing(type, item) { container.append(itemHtml); } +function removeItem(type) { + const token = localStorage.getItem('token'); + + $.ajax({ + url: '/api/avatar', + method: 'PUT', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + data: JSON.stringify({ type: type, itemId: null }), // Indicate unwearing + success: function (response) { + console.log('Avatar updated successfully.'); + $(`#avatar-${type}`).attr('src', ''); + $(`#currently-wearing [data-type="${type}"]`).remove(); + updateWearButton(type, null, false); + showAlert('info', `Unwore your ${type}.`); + }, + error: function (xhr, status, error) { + console.error('Error unwearing item:', error); + showAlert('danger', 'Error unwearing the item. Please try again later.'); + }, + }); +} + +function updateWearButton(type, itemId, isWearing) { + const wearButton = $(`.wear-item[data-type="${type}"]`); + wearButton.removeClass('btn-success').addClass('btn-primary').text('Wear'); + + if (isWearing && itemId) { + wearButton.removeClass('btn-primary').addClass('btn-success').text('Wearing'); + } +} + function loadUserAvatar() { const token = localStorage.getItem('token'); $.ajax({ @@ -246,29 +309,37 @@ function loadUserAvatar() { function saveAvatarSelection(type, itemId) { const token = localStorage.getItem('token'); - const avatarData = {}; - - switch (type) { - case 'shirt': - avatarData.shirtId = itemId; - break; - default: - return; - } + const avatarData = { type, itemId }; + console.log(`Saving avatar selection: ${type}, ID: ${itemId}`); $.ajax({ url: '/api/avatar', method: 'PUT', - data: JSON.stringify(avatarData), contentType: 'application/json', headers: { Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', }, + data: JSON.stringify(avatarData), success: function (response) { - console.log('Avatar updated successfully.'); + console.log('Avatar updated successfully:', response); + if (itemId) { + updateAvatarDisplay(type, response.avatar[`${type}Id`]); + updateCurrentlyWearing(type, response.avatar); + updateWearButton(type, itemId, true); + showAlert('success', `Wore your ${type} successfully.`); + } else { + $(`#avatar-${type}`).attr('src', ''); + $(`#currently-wearing [data-type="${type}"]`).remove(); + updateWearButton(type, null, false); + showAlert('info', `Unwore your ${type}.`); + } }, error: function (xhr, status, error) { console.error('Error updating avatar:', error); + console.error('Status:', status); + console.error('Response:', xhr.responseText); + showAlert('danger', `Error wearing ${type}. Please try again later.`); }, }); } @@ -303,6 +374,18 @@ function updateBodyColor(part, color) { // to do } +function showAlert(type, message) { + const alertHtml = ` + + `; + $('#avatar-container').prepend(alertHtml); +} + $(document).on('click', '.remove-item', function() { const type = $(this).data('type'); removeItem(type); diff --git a/client/js/user-profile.js b/client/js/user-profile.js index d1f1557..7f921e8 100644 --- a/client/js/user-profile.js +++ b/client/js/user-profile.js @@ -550,10 +550,9 @@ $(document).ready(function () { // Load user's shirts loadUserShirts(user._id); - // Initialize Bootstrap tabs + // Bootstrap tabs $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { - // You can add logic here to load items dynamically if needed - // console.log('Tab switched to: ' + $(e.target).attr('href')); + }); } @@ -565,7 +564,7 @@ $(document).ready(function () { Authorization: `Bearer ${localStorage.getItem('token')}`, }, success: function (shirts) { - displayUserShirts(shirts); + displayUserShirts(shirts, userId); }, error: function (xhr, status, error) { console.error('Error fetching user shirts:', error); @@ -576,7 +575,7 @@ $(document).ready(function () { }); } - function displayUserShirts(shirts) { + function displayUserShirts(shirts, userId) { const shirtsContainer = $('#user-shirts'); shirtsContainer.empty(); @@ -590,7 +589,8 @@ $(document).ready(function () { shirt.Name, shirt.ThumbnailLocation, shirt.creator ? shirt.creator.username : 'Unknown', - shirt.Price + shirt.Price, + shirt.creator && shirt.creator._id === userId ? 'Created' : 'Owned' ); shirtsContainer.append(shirtHtml); }); diff --git a/server/functions/api/routes/avatar.js b/server/functions/api/routes/avatar.js index f92f409..7b11c98 100644 --- a/server/functions/api/routes/avatar.js +++ b/server/functions/api/routes/avatar.js @@ -3,6 +3,7 @@ const router = express.Router(); const authenticateToken = require('../middleware/authenticateToken'); const User = require('../models/User'); const mongoose = require('mongoose'); +const Asset = require('../models/Asset'); // Get current avatar router.get('/', authenticateToken, async (req, res) => { @@ -26,35 +27,72 @@ router.get('/', authenticateToken, async (req, res) => { // Update avatar router.put('/', authenticateToken, async (req, res) => { try { - const { shirtId } = req.body; + const { type, itemId } = req.body; + console.log('Updating avatar:', { userId: req.user.userId, type, itemId }); - const user = await User.findOne({ userId: req.user.userId }); + if (!type || !['shirt', 'pants', 'hat'].includes(type)) { + console.error('Invalid or missing item type:', type); + return res.status(400).json({ error: 'Invalid or missing item type' }); + } + + const user = await User.findOne({ userId: req.user.userId }).populate('inventory'); + if (!user) { console.error('User not found for userId:', req.user.userId); return res.status(404).json({ error: 'User not found' }); } - if (shirtId) { - if (!mongoose.Types.ObjectId.isValid(shirtId)) { - console.error('Invalid shirt ID:', shirtId); - return res.status(400).json({ error: 'Invalid shirt ID' }); - } + if (!user.avatar) { + user.avatar = {}; + } + + console.log('User inventory:', user.inventory.map(item => ({ id: item._id.toString(), type: item.AssetType }))); + - // Check if the shirt is in inventory - if (!user.inventory.includes(shirtId)) { - console.error('Shirt not in user inventory:', shirtId); - return res.status(400).json({ error: 'Shirt not in user inventory' }); - } + switch (type) { + case 'shirt': + if (itemId) { + if (!mongoose.Types.ObjectId.isValid(itemId)) { + console.error('Invalid shirt ID:', itemId); + return res.status(400).json({ error: 'Invalid shirt ID' }); + } - user.avatar.shirtId = shirtId; + console.log('Checking inventory for shirt:', itemId); + + const inventoryItem = user.inventory.find(item => + item._id.toString() === itemId && item.AssetType === 'Shirt' + ); + + const createdShirt = await Asset.findOne({ + _id: itemId, + creator: user._id, + AssetType: 'Shirt' + }); + + if (!inventoryItem && !createdShirt) { + console.error('Shirt not in user inventory or not created by user:', itemId); + return res.status(400).json({ error: 'Shirt not in user inventory or not created by u' }); + } + + console.log('Setting shirt:', itemId); + user.avatar.shirt = inventoryItem; + } else { + console.log('Unwearing shirt'); + user.avatar.shirt = null; + } + break; + // cases for pants and hats can be added here later + default: + console.error('Unsupported item type:', type); + return res.status(400).json({ error: 'Unsupported item type' }); } await user.save(); - console.log('Avatar updated successfully for userId:', req.user.userId); - res.json({ message: 'Avatar updated successfully' }); + console.log('Avatar updated successfully for userId:', req.user.userId, 'New avatar:', user.avatar); + res.json({ message: 'Avatar updated successfully', avatar: user.avatar }); } catch (error) { console.error('Error updating avatar:', error); - res.status(500).json({ error: 'Internal server error', details: error.message }); + res.status(500).json({ error: 'Internal server error', details: error.message, stack: error.stack }); } }); diff --git a/server/functions/api/routes/shirt.js b/server/functions/api/routes/shirt.js index 78b7794..c090a4d 100644 --- a/server/functions/api/routes/shirt.js +++ b/server/functions/api/routes/shirt.js @@ -274,7 +274,10 @@ router.post( await thumbnailQueue.addToQueue(shirtassetId, 'Shirt'); await User.findByIdAndUpdate(req.user._id, { - $push: { shirts: shirt._id }, + $push: { + shirts: shirt._id, + inventory: shirt._id + }, }); res.status(201).json({ shirtId: shirt._id, assetId: shirt.assetId });