diff --git a/components/arcade/prizes.js b/components/arcade/prizes.js index 96f2f9bb6..766200481 100644 --- a/components/arcade/prizes.js +++ b/components/arcade/prizes.js @@ -20,6 +20,7 @@ const Prizes = ({ index, hoursBalance = null, stock, + inStock = true, ...props }) => { const parsedFulfillmentDesc = fulfillmentDescription?.replace( @@ -36,7 +37,7 @@ const Prizes = ({ return ( = 1 ? '#09AFB4' : '#808080', + background: ((hoursBalance && hoursBalance / cost >= 1) && inStock) ? '#09AFB4' : '#808080', borderRadius: '10px', flexDirection: 'column', justifyContent: 'space-between', @@ -61,11 +62,12 @@ const Prizes = ({ > = 1 ? 'none' : 'grayscale(1)' }} + sx={{ height: 'auto', maxWidth: '280px', maxHeight: '250px', filter: ((hoursBalance && hoursBalance / cost >= 1) && inStock) ? 'none' : 'grayscale(1)'}} alt={text} + /> - {stock && stock != null && stock > 0 && stock <= 100 && ( + {inStock && stock != null && stock > 0 && stock <= 100 && ( + {inStock && ( @@ -110,10 +113,10 @@ const Prizes = ({ // only show the quantity dropdown if you have enough hours to buy at least 2 of the item (hoursBalance ? hoursBalance / cost < 2 : null) ? null : ( ) } @@ -121,15 +124,15 @@ const Prizes = ({ // only show the buy button if you have enough hours to buy at least 1 of the item (hoursBalance ? hoursBalance / cost < 1 : null) ? null : ( @@ -138,6 +141,7 @@ const Prizes = ({ )} + )} - {cost} {link ? '🎟️' : cost == 1 ? 'ticket' : 'tickets'} + {cost} 🎟️ - { document.getElementById(`${parsedFullName}-info`).showModal() }} - > + > 📦 + )} 0.5 ? 1 : -1) }, []); + + const inStockItems = availableItems.filter(item => item['Stock'] === null || item['Stock'] > 0 ); + const outOfStockItems = availableItems.filter(item => item['Stock'] !== null && item['Stock'] <= 0); + return ( <> - {availableItems + {inStockItems + .sort((a, b) => a['Cost Hours'] - b['Cost Hours']) + .map((item) => ( + handleQuantityChange(item.id, q)} // Pass handler to update quantity + hoursBalance={hoursBalance} + stock={item['Stock']} + inStock={true} + /> + ))} + + Out of stock items + + {outOfStockItems .sort((a, b) => a['Cost Hours'] - b['Cost Hours']) .map((item) => ( handleQuantityChange(item.id, q)} // Pass handler to update quantity hoursBalance={hoursBalance} stock={item['Stock']} + inStock={false} /> ))} diff --git a/pages/api/arcade/shop.js b/pages/api/arcade/shop.js index ea5b62247..21eb9b3d2 100644 --- a/pages/api/arcade/shop.js +++ b/pages/api/arcade/shop.js @@ -1,14 +1,46 @@ import AirtablePlus from "airtable-plus" export const shopParts = async () => { - const airtable = new AirtablePlus({ + const baseID = "app4kCWulfB02bV8Q" + const shopItemsTable = new AirtablePlus({ apiKey: process.env.AIRTABLE_API_KEY, - baseID: "app4kCWulfB02bV8Q", + baseID, tableName: "Shop Items" }) + const ordersTable = new AirtablePlus({ + apiKey: process.env.AIRTABLE_API_KEY, + baseID, + tableName: "Orders" + }) + + const records = await shopItemsTable.read() + const newRecordsPromise = records.map(async record => { + const fields = record.fields; + let stock = fields["Stock"] + + if (stock && fields["Orders"]) { + const orderIds = fields["Orders"] + const ordersFilter = orderIds.map(id => `RECORD_ID() = "${id}"`).join(", ") + const data = await ordersTable.read({ + filterByFormula: ` + AND( + OR(${ordersFilter}), + OR( + {Status} = "Fulfilled", + {Status} = "Awaiting Fulfillment" + ) + )` + }) + + stock -= data.length; + } + return { id: record.id, ...record.fields, "Stock": (stock == null)? null : (stock >= 0 ? stock : 0) } + }) + + + const newRecords = await Promise.all(newRecordsPromise) - const records = await airtable.read() - return records.map(record => ({id: record.id, ...record.fields})) + return newRecords } export default async function handler(req, res) { @@ -21,8 +53,9 @@ export default async function handler(req, res) { description: record['Description'], hours: record['Cost Hours'], imageURL: record['Image URL'], + stock: record['Stock'], } }) - res.json(filteredData) + return res.json(filteredData) } \ No newline at end of file diff --git a/pages/arcade/[userAirtableID]/shop.js b/pages/arcade/[userAirtableID]/shop.js index 3b60630ba..9349c1b57 100644 --- a/pages/arcade/[userAirtableID]/shop.js +++ b/pages/arcade/[userAirtableID]/shop.js @@ -88,7 +88,7 @@ export async function getStaticProps({params}) { id: item.id, 'Image URL': item['Image URL'] || null, 'Max Order Quantity': item['Max Order Quantity'] || 1, - Stock: item['Stock'] || null + Stock: item['Stock'] >= 0 ? item['Stock'] : null })) props.availableItems = availableItems }), diff --git a/pages/arcade/index.js b/pages/arcade/index.js index 4ba154fa7..8a2096dc3 100644 --- a/pages/arcade/index.js +++ b/pages/arcade/index.js @@ -473,7 +473,11 @@ const Tickets = ({ title, num, text, link, bugEater, ...props }) => { {title} @@ -726,7 +730,6 @@ const FAQ = ({ question, answer }) => { }} dangerouslySetInnerHTML={{ __html: parsedAnswer }} /> - ) } @@ -880,11 +883,7 @@ function thinkingWords() { return arr[Math.floor(Math.random() * arr.length)] } -const Arcade = ({ - stickers = [], - carousel = [], - highlightedItems = [] -}) => { +const Arcade = ({ stickers = [], carousel = [], highlightedItems = [] }) => { const [showComponent, setShowComponent] = useState(false) const [showNum, setNum] = useState(false) const [showForm, setForm] = useState(false) @@ -1535,7 +1534,8 @@ const Arcade = ({ Write a programming language, receive fudge! - } + + } num="Infinite" sx={{ gridColumn: ['', 'span 2', 'span 2', 'span 2'], @@ -1553,9 +1553,7 @@ const Arcade = ({ Click me for ideas! - } + text={<>Click me for ideas!} sx={{ '&ul>li': { color: 'inherit' @@ -1663,6 +1661,7 @@ const Arcade = ({ Redeem these with your tickets! For high schoolers (or younger) only. + {/* ))} + + See all prizes! + This is just a{' '} F.A.Q. @@ -1772,7 +1799,7 @@ const Arcade = ({ /> = 0 ? item['Stock'] : null })) props.availableItems = availableItems }), diff --git a/yarn.lock b/yarn.lock index 8fe3f021b..0ea102e74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3256,9 +3256,9 @@ camelize@^1.0.0: integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ== caniuse-lite@^1.0.30001202, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001228, caniuse-lite@^1.0.30001282, caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001541: - version "1.0.30001634" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001634.tgz" - integrity sha512-fbBYXQ9q3+yp1q1gBk86tOFs4pyn/yxFm5ZNP18OXJDfA3txImOY9PhfxVggZ4vRHDqoU8NrKU81eN0OtzOgRA== + version "1.0.30001639" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001639.tgz" + integrity sha512-eFHflNTBIlFwP2AIKaYuBQN/apnUoKNhBdza8ZnW/h2di4LCZ4xFqYlxUxo+LQ76KFI1PGcC1QDxMbxTZpSCAg== caseless@~0.12.0: version "0.12.0"