diff --git a/src/extensions/arcade/index.ts b/src/extensions/arcade/index.ts index fa1193b7..0867b350 100644 --- a/src/extensions/arcade/index.ts +++ b/src/extensions/arcade/index.ts @@ -6,7 +6,9 @@ import "./slack/index.js"; import "./slack/sessions.js"; import "./slack/scrapbook.js"; import "./slack/shop.js"; -import "./slack/walkthrough.js" +import "./slack/walkthrough.js"; +import "./slack/orders.js"; + import { emitter } from "../../lib/emitter.js"; emitter.on('init', () => { diff --git a/src/extensions/arcade/slack/orders.ts b/src/extensions/arcade/slack/orders.ts new file mode 100644 index 00000000..6527b28b --- /dev/null +++ b/src/extensions/arcade/slack/orders.ts @@ -0,0 +1,38 @@ +import { AirtableAPI } from "../../../lib/airtable.js"; +import { Slack } from "../../../lib/bolt.js"; +import { Actions } from "../../../lib/constants.js"; +import { prisma } from "../../../lib/prisma.js"; +import { t } from "../../../lib/templates.js"; +import { Loading } from "../../slack/views/loading.js"; +import { Orders } from "./views/orders.js"; + +Slack.action(Actions.ORDERS, async ({ body, client }) => { + const view = await client.views.push({ + trigger_id: (body as any).trigger_id, + view: Loading.loading(), + }); + + const user = await prisma.user.findFirst({ + where: { + slackUser: { + slackId: body.user.id, + } + } + }); + + if (!user || !user.metadata.airtable) { + await Slack.views.update({ + view_id: view.view?.id, + view: Loading.error(t('error.not_a_user')) + }); + + return; + } + + const orders = await AirtableAPI.Orders.findByUser(user.metadata.airtable.id); + + await Slack.views.update({ + view_id: view.view?.id, + view: Orders.order(orders) + }); +}); \ No newline at end of file diff --git a/src/extensions/arcade/slack/shop.ts b/src/extensions/arcade/slack/shop.ts index b304a571..3cc97cb1 100644 --- a/src/extensions/arcade/slack/shop.ts +++ b/src/extensions/arcade/slack/shop.ts @@ -40,6 +40,7 @@ Slack.command(Commands.SHOP, async ({ command }) => { awaitingApproval: Math.floor(airtableUser.fields["Minutes (Pending Approval)"] / 60), inOrders: Math.floor(airtableUser.fields["In Pending (Minutes)"] / 60), spent: Math.floor(airtableUser.fields["Spent Fulfilled (Minutes)"] / 60), + verification: airtableUser.fields["Verification Status (from YSWS Verification User)"] ?? "" }) }) }); @@ -78,6 +79,7 @@ Slack.action(Actions.OPEN_SHOP, async ({ body }) => { awaitingApproval: Math.floor(airtableUser.fields["Minutes (Pending Approval)"] / 60), inOrders: Math.floor(airtableUser.fields["In Pending (Minutes)"] / 60), spent: Math.floor(airtableUser.fields["Spent Fulfilled (Minutes)"] / 60), + verification: airtableUser.fields["Verification Status (from YSWS Verification User)"] ?? "" }) }) }); \ No newline at end of file diff --git a/src/extensions/arcade/slack/views/orders.ts b/src/extensions/arcade/slack/views/orders.ts new file mode 100644 index 00000000..20e46a5c --- /dev/null +++ b/src/extensions/arcade/slack/views/orders.ts @@ -0,0 +1,54 @@ +import { KnownBlock, View } from "@slack/bolt"; +import { AirtableOrdersRead } from "../../../../lib/airtable.js"; + +export class Orders { + public static order(orders: AirtableOrdersRead[]): View { + const blocks: KnownBlock[] = []; + + if (orders.length === 0) { + blocks.push({ + type: "section", + text: { + type: "mrkdwn", + text: "You have no orders." + } + }); + } else { + for (const order of orders) { + blocks.push({ + type: "section", + text: { + type: "mrkdwn", + text: + `*${order["Item: Name"]}* +_Status:_ ${order["Status"]} +_Quantity:_ ${order["Quantity"]} +_Price:_ ${Math.floor(order["Order Price (Minutes)"] / 60)} :tw_admission_tickets:` + }, + accessory: order["Item: Image"][0] ? { + type: "image", + image_url: order["Item: Image"][0], + alt_text: order["Item: Name"][0], + } : undefined + }, { + type: "divider", + }); + } + } + + return { + type: "modal" as const, + title: { + type: "plain_text" as const, + text: "orders", + emoji: true, + }, + close: { + type: "plain_text" as const, + text: "close", + emoji: true, + }, + blocks, + }; + } +} \ No newline at end of file diff --git a/src/extensions/arcade/slack/views/shop.ts b/src/extensions/arcade/slack/views/shop.ts index a0b11248..716ba526 100644 --- a/src/extensions/arcade/slack/views/shop.ts +++ b/src/extensions/arcade/slack/views/shop.ts @@ -8,6 +8,7 @@ export class Shop { awaitingApproval, inOrders, spent, + verification // lifetime, // lifetimeTickets }: { @@ -16,6 +17,7 @@ export class Shop { awaitingApproval: number, inOrders: number, spent: number, + verification: string }): View { return { "type": "modal", @@ -67,7 +69,7 @@ _How do I get tickets?_\n- Provide { @@ -353,6 +367,22 @@ export const AirtableAPI = { // Return a list of endpoints return records.map(record => ({id: record.id, fields: record.fields as AirtableAPIRead})); } + }, + Orders: { + async findByUser(user: AirtableRecordID): Promise { + console.log(`[AirtableAPI.Orders.findByUser] Finding orders for ${user}`) + + const now = Date.now(); + + const records = await orders.select({ + filterByFormula: `{User: Record ID} = "${user}"` + }).all() + .catch(error => { console.error(error); return [] }); + + console.log(`[AirtableAPI.Orders.findByUser] Took ${Date.now() - now}ms`) + + return records.map(record => record.fields as AirtableOrdersRead); + } } }; diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 4624a32a..37d0ded4 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -113,6 +113,8 @@ export const Actions = { SESSIONS_PREVIOUS: 'sessionsprevious', SESSIONS_NEXT: 'sessionsnext', + + ORDERS: 'orders', }; export const Callbacks = {