diff --git a/client/html/pages/catalog/catalog.html b/client/html/pages/catalog/catalog.html index d64d261..90f35ec 100644 --- a/client/html/pages/catalog/catalog.html +++ b/client/html/pages/catalog/catalog.html @@ -21,25 +21,6 @@ -
@@ -50,9 +31,12 @@
-

Shirt Catalog

+
+ diff --git a/client/html/pages/catalog/shirt-details.html b/client/html/pages/catalog/shirt-details.html index 8ba2c16..01299dd 100644 --- a/client/html/pages/catalog/shirt-details.html +++ b/client/html/pages/catalog/shirt-details.html @@ -24,7 +24,9 @@
-
+
+ +
diff --git a/client/js/catalog.js b/client/js/catalog.js index 7663887..7cc8eff 100644 --- a/client/js/catalog.js +++ b/client/js/catalog.js @@ -20,25 +20,37 @@ function displayShirts(shirts) { shirtsContainer.empty(); if (shirts.length === 0) { - shirtsContainer.append('

No shirts available in the catalog.

'); + shirtsContainer.append('
No shirts available in the catalog.
'); return; } - shirts.forEach(shirt => { - const shirtCard = ` -
-
- ${shirt.Name} -
-
${shirt.Name}
-

Creator: ${shirt.creator ? shirt.creator.username : 'Unknown'}

-

Price: ${shirt.Price} currency

-

For Sale: ${shirt.IsForSale ? 'Yes' : 'No'}

- View Details + shirts.forEach((shirt, index) => { + const shirtPanel = ` +
+
+
+

${shirt.Name}

+
+
+ ${shirt.Name} +
+

Creator: ${shirt.creator ? shirt.creator.username : 'Unknown'}

+

Price: ${shirt.Price} currency

+

For Sale: ${shirt.IsForSale ? 'Yes' : 'No'}

+
+
`; - shirtsContainer.append(shirtCard); + shirtsContainer.append(shirtPanel); + + if ((index + 1) % 4 === 0) { + shirtsContainer.append('
'); + } + if ((index + 1) % 2 === 0) { + shirtsContainer.append('
'); + } }); } \ No newline at end of file diff --git a/client/js/shirt-details.js b/client/js/shirt-details.js index e24da69..65a8915 100644 --- a/client/js/shirt-details.js +++ b/client/js/shirt-details.js @@ -22,23 +22,66 @@ function displayShirtDetails(shirt) { const shirtDetailsContainer = $('#shirt-details'); const isOwner = shirt.creator._id === localStorage.getItem('userId'); const detailsHtml = ` -

${shirt.Name}

- ${shirt.Name} -

${shirt.Description}

-

Creator: ${shirt.creator ? shirt.creator.username : 'Unknown'}

-

Price: ${shirt.Price} currency

-

For Sale: ${shirt.IsForSale ? 'Yes' : 'No'}

- ${isOwner ? '

You own this shirt

' : (shirt.IsForSale ? '' : '')} +
+
+ ${shirt.Name} +
+
+
+

${shirt.Name}

+

By ${shirt.creator ? shirt.creator.username : 'Unknown'}

+
+
+

Description

+

${shirt.Description}

+
+
+
+

Shirt Details

+
+
+

Price: ${shirt.Price} currency

+

For Sale: ${shirt.IsForSale ? 'Yes' : 'No'}

+
+
+
+
`; shirtDetailsContainer.html(detailsHtml); - if (!isOwner && shirt.IsForSale) { - $('#purchase-btn').on('click', function() { - purchaseShirt(shirt._id); - }); - } + checkOwnership(shirt._id); } +function checkOwnership(shirtId) { + $.ajax({ + url: `/api/shirts/check-ownership/${shirtId}`, + method: 'GET', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + success: function(response) { + if (response.owned) { + $('#purchase-section').html('
You own this shirt
'); + } else if (response.isCreator) { + $('#purchase-section').html('
You are the creator of this shirt
'); + } else { + // Use response.price instead of shirt.Price + $('#purchase-section').html(` + + `); + $('#purchase-btn').on('click', function() { + purchaseShirt(shirtId); + }); + } + }, + error: function(xhr, status, error) { + console.error('Error checking shirt ownership:', error); + $('#purchase-section').html('
Error checking ownership status
'); + } + }); +} function purchaseShirt(shirtId) { $.ajax({ url: `/api/shirts/purchase/${shirtId}`, @@ -47,16 +90,31 @@ function purchaseShirt(shirtId) { 'Authorization': `Bearer ${localStorage.getItem('token')}` }, success: function(response) { - alert('Shirt purchased successfully!'); + showAlert('success', 'Shirt purchased successfully!'); updateCurrency(response.newBalance); loadShirtDetails(shirtId); // Reload shirt details to update the UI }, error: function(xhr, status, error) { - alert('Error purchasing shirt: ' + xhr.responseJSON.error); + console.error('Error purchasing shirt:', xhr.responseJSON); + let errorMessage = 'Error purchasing shirt. Please try again later.'; + if (xhr.responseJSON && xhr.responseJSON.error) { + errorMessage = xhr.responseJSON.error; + } + showAlert('danger', errorMessage); } }); } function updateCurrency(newBalance) { $('#currency-amount').text(newBalance); +} + +function showAlert(type, message) { + const alertHtml = ` + + `; + $('#shirt-details').prepend(alertHtml); } \ No newline at end of file diff --git a/client/js/user-profile.js b/client/js/user-profile.js index f16c466..f576463 100644 --- a/client/js/user-profile.js +++ b/client/js/user-profile.js @@ -465,21 +465,22 @@ $(document).ready(function () { function loadUserShirts(userId) { $.ajax({ - url: `/api/shirts/user/${userId}`, - method: 'GET', - headers: { - 'Authorization': `Bearer ${localStorage.getItem('token')}` - }, - success: function(shirts) { - displayUserShirts(shirts); - }, - error: function(xhr, status, error) { - console.error('Error fetching user shirts:', error); - } + url: `/api/shirts/user/id/${userId}`, // Updated URL + method: 'GET', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + success: function(shirts) { + displayUserShirts(shirts); + }, + error: function(xhr, status, error) { + console.error('Error fetching user shirts:', error); + $('#user-shirts').html('

Error loading your shirts. Please try again later.

'); + } }); -} + } -function displayUserShirts(shirts) { + function displayUserShirts(shirts) { const shirtsContainer = $('#user-shirts'); shirtsContainer.empty(); diff --git a/server/functions/api/models/User.js b/server/functions/api/models/User.js index 7e91786..5c4bb40 100644 --- a/server/functions/api/models/User.js +++ b/server/functions/api/models/User.js @@ -116,6 +116,11 @@ forumPostCount: { default: 0 }, +inventory: [{ + type: mongoose.Schema.Types.ObjectId, + ref: 'Asset' +}], + }); diff --git a/server/functions/api/routes/shirt.js b/server/functions/api/routes/shirt.js index b25bc73..ea12ec9 100644 --- a/server/functions/api/routes/shirt.js +++ b/server/functions/api/routes/shirt.js @@ -213,34 +213,90 @@ router.get('/catalog', async (req, res) => { router.post('/purchase/:id', authenticateToken, async (req, res) => { try { - const shirt = await Asset.findOne({ _id: req.params.id, AssetType: 'Shirt', IsForSale: 1 }); - if (!shirt) { - return res.status(404).json({ error: 'Shirt not found or not for sale' }); - } + const shirt = await Asset.findOne({ _id: req.params.id, AssetType: 'Shirt', IsForSale: 1 }); + if (!shirt) { + return res.status(404).json({ error: 'Shirt not found or not for sale' }); + } - const user = await User.findById(req.user.userId); - if (user.currency < shirt.Price) { - return res.status(400).json({ error: 'Insufficient funds' }); - } + const user = await User.findById(req.user.userId); + if (!user) { + return res.status(404).json({ error: 'User not found' }); + } - if (shirt.creator.toString() === user._id.toString()) { - return res.status(400).json({ error: 'You already own this shirt' }); - } + if (user.inventory && user.inventory.includes(shirt._id)) { + return res.status(400).json({ error: 'You already own this shirt' }); + } - user.currency -= shirt.Price; - user.inventory.push(shirt._id); - await user.save(); + if (user.currency < shirt.Price) { + return res.status(400).json({ error: 'Insufficient funds' }); + } - shirt.Sales += 1; - await shirt.save(); + if (shirt.creator.toString() === user._id.toString()) { + return res.status(400).json({ error: 'You already own this shirt' }); + } + + user.currency -= shirt.Price; + + if (!user.inventory) { + user.inventory = []; + } + + user.inventory.push(shirt._id); + await user.save(); - res.json({ success: true, newBalance: user.currency }); + shirt.Sales += 1; + await shirt.save(); + + res.json({ success: true, newBalance: user.currency }); } catch (error) { - console.error('Error purchasing shirt:', error); - res.status(500).json({ error: 'Internal server error' }); + console.error('Error purchasing shirt:', error); + res.status(500).json({ error: 'Internal server error', details: error.message }); } }); - +router.get('/check-ownership/:id', authenticateToken, async (req, res) => { + try { + const shirt = await Asset.findOne({ _id: req.params.id, AssetType: 'Shirt' }); + if (!shirt) { + return res.status(404).json({ error: 'Shirt not found' }); + } + + const user = await User.findById(req.user.userId); + if (!user) { + return res.status(404).json({ error: 'User not found' }); + } + + const owned = user.inventory && user.inventory.includes(shirt._id); + const isCreator = shirt.creator.toString() === user._id.toString(); + + // Include the shirt's price in the response + res.json({ owned, isCreator, price: shirt.Price }); + } catch (error) { + console.error('Error checking shirt ownership:', error); + res.status(500).json({ error: 'Internal server error', details: error.message }); + } +}); + +router.get('/user/id/:id', authenticateToken, async (req, res) => { + try { + const userId = req.params.id; + const user = await User.findById(userId); + if (!user) { + return res.status(404).json({ error: 'User not found' }); + } + + const createdShirts = await Asset.find({ creator: userId, AssetType: 'Shirt' }).sort({ createdAt: -1 }); + const ownedShirts = await Asset.find({ _id: { $in: user.inventory }, AssetType: 'Shirt' }).sort({ createdAt: -1 }); + const allShirts = [...createdShirts, ...ownedShirts]; + const uniqueShirts = Array.from(new Set(allShirts.map(s => s._id.toString()))) + .map(_id => allShirts.find(s => s._id.toString() === _id)); + + res.json(uniqueShirts); + } catch (error) { + console.error('Error fetching user shirts by ID:', error); + res.status(500).json({ error: 'Internal server error' }); + } +}); + router.get('/user', authenticateToken, async (req, res) => { try { const shirts = await Asset.find({ creator: req.user.userId, AssetType: 'Shirt' }).sort({ updatedAt: -1 });