Skip to content

Add basic escape room ordering functionality with Stripe integration#433

Open
racecn wants to merge 30 commits intomainfrom
nathan/escape-room-subsite-ordering
Open

Add basic escape room ordering functionality with Stripe integration#433
racecn wants to merge 30 commits intomainfrom
nathan/escape-room-subsite-ordering

Conversation

@racecn
Copy link
Contributor

@racecn racecn commented Nov 6, 2025

Added support for online ordering of escape room kits, including:

  • Stripe payment integration
  • Netlify configuration for deployment and serverless functions.
  • Vitest configuration astro/vite.config.ts for testing.

Main content access can be found at /services/escape-room/access
README is located here \local-dev\README.md with more information on simulating purchase information.
Test purchases can be simulated using the provided JSON format, this will need to be converted to use the future AzureDB system.

racecn added 18 commits August 28, 2025 14:20
…ndling and Stripe integration

- Implemented the purchase page layout and form for selecting kit type and theme.
- Integrated Stripe for payment processing with a backend API for creating checkout sessions.
- Added validation for form inputs and error handling for payment processing.
- Created Azure functions for handling checkout session creation and retrieval.
- Implemented storage of purchase data in Azure Table Storage with proof code generation.
- Added environment configuration example for Stripe and Azure settings.
… handling

- Added session-status API to retrieve payment status using Stripe Checkout session ID.
- Implemented Stripe webhook to handle checkout session completion and store purchase data.
- Created verify-purchase API to validate purchase codes and manage user sessions.
- Developed access.astro page for users to access their purchased escape room kits.
- Configured Netlify deployment settings and added necessary environment variables.
- Updated package.json and package-lock.json to include Stripe and UUID dependencies.

feat: Basic implementation of post-purchase page according to Figma
Configure Vitest with a setup file and path alias for cleaner imports.
- Removed the digital content API endpoint and its associated logic.
- Simplified the escape room access page, enhancing the form for purchase code and email verification.
- Added error handling for missing content in the new corporate escape room content page.
- Introduced a new layout for displaying escape room content based on user sessions.
@racecn racecn added this to the Escape Room Subsite milestone Nov 6, 2025
@racecn racecn linked an issue Nov 6, 2025 that may be closed by this pull request
@netlify
Copy link

netlify bot commented Nov 6, 2025

Deploy Preview for accessiblecommunity failed.

Name Link
🔨 Latest commit 80f9b96
🔍 Latest deploy log https://app.netlify.com/projects/accessiblecommunity/deploys/698e3b14917a86000803f921

# Allow basic materials
Allow: /materials/basic/

Sitemap: https://accessiblecommunity.github.io/sitemap.xml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sitemap-0.xml should be the right path

Disallow: /api/verify-purchase

# Allow basic materials
Allow: /materials/basic/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on Allow: * and then the disallows? That way you automatically allow everything to be crawled and only have to disallow that which we don't want

const price = kitType === 'build' ? 50000 : 350000; // Stripe uses cents
const kitTypeName = kitType === 'build' ? 'Build-your-own Kit' : 'Ready-made Kit';

// Map theme values to display names
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to pull these from a content collection, so we don't have to hardcode them.

<fieldset class="mb-4">
<legend class="h5">Choose Your Theme *</legend>
<div class="row gy-3">
<div class="col-sm-6">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be able to generate these from a content collection of some type.

</ThemedSection>

<!-- Ready-Made Kit Coming Soon Section -->
<ThemedSection theme="secondary">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need these, we are no longer doing ready-made kits.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you made this an actual endpoint and not a function?

// Export for use in save-purchase-data
export { handleSuccessfulPayment };

async function storePurchaseData(purchaseData: any) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably will want to separate this out into a separate lib, like you did for the session memory store.

return [...new Set(candidates.filter(Boolean) as string[])];
}

async function loadPurchase(purchaseCode: string): Promise<PurchaseRecord | null> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably go in the same lib as the savePurchaseData function, so it can be easily rewritten to a DB or whatever.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be generic, or tied directly to each kit?

{
userAgent: '*',
allow: ['/'],
allow: ['/', '/materials/basic/'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, do we have to explicitly allow /materials/basic even though we don't disallow it below?

<div class="container">
<div class="row g-4">
<div class="col-md-4">
<h3 class="h5">About Accessible Community</h3>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we always guarantee the heading right before this one is an h2?

margin: 2rem 0;
}

@media (max-width: 991.98px) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this value for max-width? Do you want it in px?

padding: 3rem 0 1.5rem;
}

.escape-room-footer .col-md-4 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use owl selector/the stack approach if you wanted to not have to set last child explicitly to 0rem. This is good too though!
https://every-layout.dev/layouts/stack/

</main>

<script>
// @ts-nocheck
Copy link
Contributor

@courtneylinder courtneylinder Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on this code being it's own js file? Maybe some code comments too for what it's calculating just so it's quicker to read?

// - Mailgun
// etc.

// For now, we'll just log the email content
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to update this before release?

const tokenData = downloadTokens.get(downloadToken);

if (!tokenData || Date.now() > tokenData.expiresAt || tokenData.used) {
if (tokenData) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make the above !tokenData into a && somehow so we don't have to do another check right after for if tokenData does exist?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Ordering capability for the Escape Room subsite

3 participants

Comments