Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
a30a864
type fix
BilalG1 Aug 20, 2025
d6397fa
custom customer type
BilalG1 Aug 20, 2025
5e5c0ae
merge dev
BilalG1 Aug 20, 2025
d0e4e09
small fixes
BilalG1 Aug 20, 2025
1018ee5
fix test
BilalG1 Aug 20, 2025
553ffe0
fix issues
BilalG1 Aug 20, 2025
7e95b6b
revert import changes
BilalG1 Aug 20, 2025
da6f000
fix test
BilalG1 Aug 20, 2025
4b79dd1
offer and item pages, edits, deletes
BilalG1 Aug 20, 2025
4c546b8
fix lint
BilalG1 Aug 20, 2025
c22bf3c
small fixes
BilalG1 Aug 21, 2025
2b19be0
fix copy
BilalG1 Aug 21, 2025
03c06a2
payments test mode
BilalG1 Aug 21, 2025
19d1d52
revoke codes
BilalG1 Aug 21, 2025
582f876
fix test
BilalG1 Aug 21, 2025
8626012
stackable purchases
BilalG1 Aug 21, 2025
d5f0dd4
server only offers
BilalG1 Aug 21, 2025
82ff799
seed extra-admins, small fixes
BilalG1 Aug 21, 2025
eb7ee91
wip
BilalG1 Aug 22, 2025
1a3b465
updated schema
N2D4 Aug 22, 2025
40ff247
Include by default price
N2D4 Aug 22, 2025
4645d09
Combine subscriptions from DB and include-by-default
N2D4 Aug 22, 2025
3488427
wip updated schema
BilalG1 Aug 23, 2025
101c98a
schema fixes, ledger transactions
BilalG1 Aug 25, 2025
b27c7c8
merge dev
BilalG1 Aug 25, 2025
e537f6b
type fixes
BilalG1 Aug 25, 2025
2198b63
Separate Stripe account ID from schema
N2D4 Aug 25, 2025
9a5ac32
Merge branch 'payments-tx-ledger-algo' into payments-separate-stripe-…
N2D4 Aug 25, 2025
54bdf9a
Update AGENTS.md
N2D4 Aug 25, 2025
d10452d
Make CLAUDE.md an alias
N2D4 Aug 25, 2025
5e2b22a
fix tests and getSubscriptions
BilalG1 Aug 26, 2025
90c0b24
Merge remote-tracking branch 'origin/payments-separate-stripe-account…
BilalG1 Aug 26, 2025
dd749d9
more
N2D4 Aug 26, 2025
dfdd231
type fix
BilalG1 Aug 26, 2025
8545274
fix stripe account info
BilalG1 Aug 26, 2025
59d375b
fix tests
BilalG1 Aug 26, 2025
4b7f823
fix tests
BilalG1 Aug 26, 2025
959dac2
UX updates
N2D4 Aug 26, 2025
ee93553
fix tests
BilalG1 Aug 26, 2025
a3beae8
UX changes
N2D4 Aug 26, 2025
786855f
fixes
N2D4 Aug 26, 2025
7ce7254
globe
N2D4 Aug 26, 2025
633e2e0
Dummy data toggle
N2D4 Aug 26, 2025
05095aa
dots
N2D4 Aug 26, 2025
8eab0e6
Various
N2D4 Aug 26, 2025
3ce3ce9
more stuff
N2D4 Aug 26, 2025
7f2c646
Better groups
N2D4 Aug 26, 2025
eadbd6f
more fixes...
N2D4 Aug 26, 2025
6e1a689
Merge dev into payments-tx-ledger-algo
N2D4 Aug 26, 2025
c496ee3
Merge branch 'payments-tx-ledger-algo' into payments-separate-stripe-…
N2D4 Aug 26, 2025
0420aa3
fix tests
BilalG1 Aug 26, 2025
f01efbb
Merge branch 'payments-tx-ledger-algo' of https://github.com/stack-au…
BilalG1 Aug 26, 2025
b36ed7e
fix createCheckoutUrl
BilalG1 Aug 26, 2025
3d0d056
Fixes
N2D4 Aug 26, 2025
4c8d2de
Better list hover
N2D4 Aug 26, 2025
72beb13
Improve onboarding screen
N2D4 Aug 26, 2025
157c024
payments fixes
BilalG1 Aug 27, 2025
6f6d8e2
fixes
N2D4 Aug 27, 2025
7b2ac57
validate-code extra info
BilalG1 Aug 27, 2025
c878b3f
Merge branch 'dev' into payments-tx-ledger-algo
N2D4 Aug 27, 2025
33f1afc
Merge branch 'payments-tx-ledger-algo' into payments-separate-stripe-…
N2D4 Aug 27, 2025
afce228
fix mapProperty
N2D4 Aug 27, 2025
d5eb23c
fix mapProperty
N2D4 Aug 27, 2025
e50082f
more fixes
N2D4 Aug 27, 2025
c815d99
Welcome screen
N2D4 Aug 27, 2025
28523cd
Pushes
N2D4 Aug 27, 2025
3c3a8f2
More fixes
N2D4 Aug 27, 2025
c0b1094
More
N2D4 Aug 27, 2025
3de5eda
Merge branch 'dev' into payments-separate-stripe-account-id-from-schema
N2D4 Aug 27, 2025
844a986
fix test
BilalG1 Aug 27, 2025
aed61b5
fix conflicts
BilalG1 Aug 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ To see all development ports, refer to the index.html of `apps/dev-launchpad/pub
- Environment variables are pre-configured in `.env.development` files
- Always run typecheck, lint, and test to make sure your changes are working as expected. You can save time by only linting and testing the files you've changed (and/or related E2E tests).
- The project uses a custom route handler system in the backend for consistent API responses
- Sometimes, the typecheck will give errors along the line of "Cannot assign Buffer to Uint8Array" or similar, on changes that are completely unrelated to your own changes. If that happens, tell the user to run `pnpm clean && pnpm i && pnpm run codegen && pnpm build:packages`, and restart the dev server (you cannot run this yourself). After that's done, the typecheck should pass.
- When writing tests, prefer .toMatchInlineSnapshot over other selectors, if possible. You can check (and modify) the snapshot-serializer.ts file to see how the snapshots are formatted and how non-deterministic values are handled.
- Whenever you learn something new, or at the latest right before you call the `Stop` tool, write whatever you learned into the ./claude/CLAUDE-KNOWLEDGE.md file, in the Q&A format in there. You will later be able to look up knowledge from there (based on the question you asked).
- Animations: Keep hover/click transitions snappy and fast. Don't delay the action with a pre-transition (e.g. no fade-in when hovering a button) — it makes the UI feel sluggish. Instead, apply transitions after the action, like a smooth fade-out when the hover ends.

### Code-related
- Use ES6 maps instead of records wherever you can.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { getStackStripe } from "@/lib/stripe";
import { globalPrismaClient } from "@/prisma-client";
import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler";
import { KnownErrors } from "@stackframe/stack-shared";
import { adaptSchema, adminAuthTypeSchema, yupBoolean, yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
import { StatusError } from "@stackframe/stack-shared/dist/utils/errors";

export const GET = createSmartRouteHandler({
metadata: {
Expand Down Expand Up @@ -32,11 +32,7 @@ export const GET = createSmartRouteHandler({
});

if (!project?.stripeAccountId) {
return {
statusCode: 200,
bodyType: "json",
body: null,
};
throw new KnownErrors.StripeAccountInfoNotFound();
}

const stripe = getStackStripe();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,9 @@ export function GlobeSection({ countryData, totalUsers, children }: {countryData
}
const controls = current.controls();
controls.maxDistance = 1000;
controls.minDistance = 400;
controls.minDistance = 200;
controls.dampingFactor = 0.2;
current.camera().position.z = 500;
// even though rendering is resumed by default, we want to pause it after 200ms, so call resumeRender()
Comment on lines 184 to 188
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure OrbitControls damping is enabled and state synced after camera mutation

Without enableDamping, dampingFactor is ignored. After programmatic camera changes, call controls.update() to avoid a first-interaction "jump."

   const controls = current.controls();
   controls.maxDistance = 1000;
   controls.minDistance = 200;
-  controls.dampingFactor = 0.2;
+  controls.dampingFactor = 0.2;
+  controls.enableDamping = true;
   current.camera().position.z = 500;
+  controls.update();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
controls.maxDistance = 1000;
controls.minDistance = 400;
controls.minDistance = 200;
controls.dampingFactor = 0.2;
current.camera().position.z = 500;
// even though rendering is resumed by default, we want to pause it after 200ms, so call resumeRender()
const controls = current.controls();
controls.maxDistance = 1000;
controls.minDistance = 200;
controls.dampingFactor = 0.2;
controls.enableDamping = true;
current.camera().position.z = 500;
controls.update();
// even though rendering is resumed by default, we want to pause it after 200ms, so call resumeRender()
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/globe.tsx
around lines 184-188, OrbitControls has dampingFactor set but enableDamping is
not enabled and the controls are not updated after programmatic camera changes;
set controls.enableDamping = true immediately after creating/configuring
controls so dampingFactor takes effect, and call controls.update() after
mutating the camera (e.g., after current.camera().position.z = 500 and after
changing min/maxDistance) to sync internal state and prevent a first-interaction
jump.

resumeRender();
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export function PageLayout(props: {
width?: number,
})) {
return (
<div className="py-4 px-4 md:px-6 flex justify-center">
<div className="py-4 px-4 md:px-6 flex justify-center flex-1">
<div
className={"min-w-0"}
className={"min-w-0 flex flex-col"}
style={{
maxWidth: props.fillWidth ? undefined : (props.width ?? 1250),
width: props.fillWidth ? '100%' : (props.width ?? 1250),
Expand All @@ -33,7 +33,7 @@ export function PageLayout(props: {
</div>
{props.actions}
</div>
<div className="mt-4 flex flex-col gap-4">
<div className="mt-4 flex flex-col gap-4 flex-1">
{props.children}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
"use client";

import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Input, Label, Typography, SimpleTooltip } from "@stackframe/stack-ui";
import { useState } from "react";

type CreateGroupDialogProps = {
open: boolean,
onOpenChange: (open: boolean) => void,
onCreate: (group: { id: string, displayName: string }) => void,
};

export function CreateGroupDialog({ open, onOpenChange, onCreate }: CreateGroupDialogProps) {
const [groupId, setGroupId] = useState("");
const [displayName, setDisplayName] = useState("");
const [errors, setErrors] = useState<{ id?: string, displayName?: string }>({});

const validateAndCreate = () => {
const newErrors: { id?: string, displayName?: string } = {};

// Validate group ID
if (!groupId.trim()) {
newErrors.id = "Group ID is required";
} else if (!/^[a-z0-9-]+$/.test(groupId)) {
newErrors.id = "Group ID must contain only lowercase letters, numbers, and hyphens";
}

// Validate display name
if (!displayName.trim()) {
newErrors.displayName = "Display name is required";
}

if (Object.keys(newErrors).length > 0) {
setErrors(newErrors);
return;
}

onCreate({ id: groupId.trim(), displayName: displayName.trim() });

// Reset form
setGroupId("");
setDisplayName("");
setErrors({});
onOpenChange(false);
};

const handleClose = () => {
setGroupId("");
setDisplayName("");
setErrors({});
onOpenChange(false);
};

return (
<Dialog open={open} onOpenChange={handleClose}>
<DialogContent className="sm:max-w-[425px]">
Comment on lines +53 to +55
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Bug: onOpenChange forces close and prevents proper open-state control.

Pass through the next state; only reset when closing.

Apply:

-    <Dialog open={open} onOpenChange={handleClose}>
+    <Dialog
+      open={open}
+      onOpenChange={(next) => next ? onOpenChange(true) : handleClose()}
+    >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (
<Dialog open={open} onOpenChange={handleClose}>
<DialogContent className="sm:max-w-[425px]">
return (
<Dialog
open={open}
onOpenChange={(next) => next ? onOpenChange(true) : handleClose()}
>
<DialogContent className="sm:max-w-[425px]">
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/payments/create-group-dialog.tsx
around lines 53–55, the Dialog's onOpenChange currently forces close and
prevents proper controlled open-state; update the handler to accept the next
open state (e.g., nextOpen) and pass it through: when nextOpen is false call
your existing close/reset logic, otherwise set/keep the open state (do not
force-close); ensure the component remains a properly controlled Dialog by
wiring the handler to forward the new state rather than always resetting.

<DialogHeader>
<DialogTitle>Create Offer Group</DialogTitle>
<DialogDescription>
Offer groups allow you to organize related offers. Customers can only have one active offer from each group at a time (except for add-ons).
</DialogDescription>
</DialogHeader>

<div className="grid gap-4 py-4">
<div className="grid gap-2">
<Label htmlFor="group-id">
<SimpleTooltip tooltip="This is the unique identifier for your group, used in code">
Group ID
</SimpleTooltip>
</Label>
<Input
id="group-id"
value={groupId}
onChange={(e) => {
setGroupId(e.target.value);
setErrors(prev => ({ ...prev, id: undefined }));
}}
placeholder="e.g., pricing-tiers"
className={errors.id ? "border-destructive" : ""}
/>
{errors.id && (
<Typography type="label" className="text-destructive">
{errors.id}
</Typography>
)}
</div>

<div className="grid gap-2">
<Label htmlFor="display-name">
<SimpleTooltip tooltip="This is how the group will be displayed to users">
Display Name
</SimpleTooltip>
</Label>
<Input
id="display-name"
value={displayName}
onChange={(e) => {
setDisplayName(e.target.value);
setErrors(prev => ({ ...prev, displayName: undefined }));
}}
placeholder="e.g., Pricing Tiers"
className={errors.displayName ? "border-destructive" : ""}
/>
{errors.displayName && (
<Typography type="label" className="text-destructive">
{errors.displayName}
</Typography>
)}
</div>
</div>

<DialogFooter>
<Button variant="outline" onClick={handleClose}>
Cancel
</Button>
<Button onClick={validateAndCreate}>
Create Group
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}

Loading
Loading