Skip to content

Commit e730f95

Browse files
committed
next/store/course: rename type to source, to be later able to distinquish where to route back
1 parent 3a8af73 commit e730f95

File tree

19 files changed

+327
-125
lines changed

19 files changed

+327
-125
lines changed

src/.claude/settings.local.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
"Bash(pnpm build:*)",
66
"Bash(git add:*)",
77
"Bash(git commit:*)",
8-
"Bash(prettier -w:*)"
8+
"Bash(prettier -w:*)",
9+
"WebFetch(domain:docs.anthropic.com)",
10+
"Bash(pnpm ts-build:*)",
11+
"Bash(find:*)"
912
],
1013
"deny": []
1114
}

src/CLAUDE.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# CLAUDE.md
1+
# CLAUDE.md and GEMINI.md
22

3-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
3+
This file provides guidance to Claude Code (claude.ai/code) and also Gemini CLI (https://github.com/google-gemini/gemini-cli) when working with code in this repository.
44

55
# CoCalc Source Repository
66

@@ -43,7 +43,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
4343

4444
### Development
4545

46-
- After code changes, run `pretter -w [filename]` to ensure consistent styling
46+
- **IMPORTANT**: Always run `prettier -w [filename]` immediately after editing any .ts, .tsx, .md, or .json file to ensure consistent styling
4747
- After TypeScript or `*.tsx` changes, run `pnpm build` in the relevant package directory
4848

4949
## Architecture Overview
@@ -87,6 +87,7 @@ CoCalc is organized as a monorepo with key packages:
8787
- **Database Queries**: Structured query system with typed interfaces
8888
- **Event Emitters**: Inter-service communication within backend
8989
- **REST-like APIs**: Some HTTP endpoints for specific operations
90+
- **API Schema**: API endpoints in `packages/next/pages/api/v2/` use Zod schemas in `packages/next/lib/api/schema/` for validation. These schemas must be kept in harmony with the TypeScript types sent from frontend applications using `apiPost` (in `packages/next/lib/api/post.ts`) or `api` (in `packages/frontend/client/api.ts`). When adding new fields to API requests, both the frontend types and the API schema validation must be updated.
9091

9192
### Key Technologies
9293

src/GEMINI.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# CLAUDE.md and GEMINI.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) and also Gemini CLI (https://github.com/google-gemini/gemini-cli) when working with code in this repository.
4+
5+
# CoCalc Source Repository
6+
7+
- This is the source code of CoCalc in a Git repository
8+
- It is a complex JavaScript/TypeScript SaaS application
9+
- CoCalc is organized as a monorepository (multi-packages) in the subdirectory "./packages"
10+
- The packages are managed as a pnpm workspace in "./packages/pnpm-workspace.yaml"
11+
12+
## Code Style
13+
14+
- Everything is written in TypeScript code
15+
- Indentation: 2-spaces
16+
- Run `pretter -w [filename]` after modifying a file (ts, tsx, md, json, ...) to format it correctly.
17+
- All .js and .ts files are formatted by the tool prettier
18+
- Add suitable types when you write code
19+
- Variable name styles are "camelCase" for local and "FOO_BAR" for global variables. If you edit older code not following these guidlines, adjust this rule to fit the files style.
20+
- Some older code is JavaScript or CoffeeScript, which will be translated to TypeScript
21+
- Use ES modules (import/export) syntax, not CommonJS (require)
22+
- Organize the list of imports in such a way: installed npm packages are on top, newline, then are imports from @cocalc's code base. Sorted alphabetically.
23+
24+
## Development Commands
25+
26+
### Essential Commands
27+
28+
- `pnpm build-dev` - Build all packages for development
29+
- `pnpm clean` - Clean all node_modules and dist directories
30+
- `pnpm test` - Run full test suite
31+
- `pnpm depcheck` - Check for dependency issues
32+
- `prettier -w [filename]` to format the style of a file after editing it
33+
- after creating a file, run `git add [filename]` to start tracking it
34+
35+
### Package-Specific Commands
36+
37+
- `cd packages/[package] && pnpm build` - Build and compile a specific package
38+
- for packages/next and packages/static, run `cd packages/[package] && pnpm build-dev`
39+
- `cd packages/[package] && pnpm tsc:watch` - TypeScript compilation in watch mode for a specific package
40+
- `cd packages/[package] && pnpm test` - Run tests for a specific package
41+
- `cd packages/[package] && pnpm build` - Build a specific package
42+
- **IMPORTANT**: When modifying packages like `util` that other packages depend on, you must run `pnpm build` in the modified package before typechecking dependent packages
43+
44+
### Development
45+
46+
- **IMPORTANT**: Always run `prettier -w [filename]` immediately after editing any .ts, .tsx, .md, or .json file to ensure consistent styling
47+
- After TypeScript or `*.tsx` changes, run `pnpm build` in the relevant package directory
48+
49+
## Architecture Overview
50+
51+
### Package Structure
52+
53+
CoCalc is organized as a monorepo with key packages:
54+
55+
- **frontend** - React/TypeScript frontend application using Redux-style stores and actions
56+
- **backend** - Node.js backend services and utilities
57+
- **hub** - Main server orchestrating the entire system
58+
- **database** - PostgreSQL database layer with queries and schema
59+
- **util** - Shared utilities and types used across packages
60+
- **comm** - Communication layer including WebSocket types
61+
- **conat** - CoCalc's container/compute orchestration system
62+
- **sync** - Real-time synchronization system for collaborative editing
63+
- **project** - Project-level services and management
64+
- **static** - Static assets and build configuration
65+
- **next** - Next.js server components
66+
67+
### Key Architectural Patterns
68+
69+
#### Frontend Architecture
70+
71+
- **Redux-style State Management**: Uses custom stores and actions pattern (see `packages/frontend/app-framework/actions-and-stores.ts`)
72+
- **TypeScript React Components**: All frontend code is TypeScript with proper typing
73+
- **Modular Store System**: Each feature has its own store/actions (AccountStore, BillingStore, etc.)
74+
- **WebSocket Communication**: Real-time communication with backend via WebSocket messages
75+
76+
#### Backend Architecture
77+
78+
- **PostgreSQL Database**: Primary data store with sophisticated querying system
79+
- **WebSocket Messaging**: Real-time communication between frontend and backend
80+
- **Conat System**: Container orchestration for compute servers
81+
- **Event-Driven Architecture**: Extensive use of EventEmitter patterns
82+
- **Microservice-like Packages**: Each package handles specific functionality
83+
84+
#### Communication Patterns
85+
86+
- **WebSocket Messages**: Primary communication method (see `packages/comm/websocket/types.ts`)
87+
- **Database Queries**: Structured query system with typed interfaces
88+
- **Event Emitters**: Inter-service communication within backend
89+
- **REST-like APIs**: Some HTTP endpoints for specific operations
90+
- **API Schema**: API endpoints in `packages/next/pages/api/v2/` use Zod schemas in `packages/next/lib/api/schema/` for validation. These schemas must be kept in harmony with the TypeScript types sent from frontend applications using `apiPost` (in `packages/next/lib/api/post.ts`) or `api` (in `packages/frontend/client/api.ts`). When adding new fields to API requests, both the frontend types and the API schema validation must be updated.
91+
92+
### Key Technologies
93+
94+
- **TypeScript**: Primary language for all new code
95+
- **React**: Frontend framework
96+
- **PostgreSQL**: Database
97+
- **Node.js**: Backend runtime
98+
- **WebSockets**: Real-time communication
99+
- **pnpm**: Package manager and workspace management
100+
- **Jest**: Testing framework
101+
- **SASS**: CSS preprocessing
102+
103+
### Database Schema
104+
105+
- Comprehensive schema in `packages/util/db-schema`
106+
- Query abstractions in `packages/database/postgres/`
107+
- Type-safe database operations with TypeScript interfaces
108+
109+
### Testing
110+
111+
- **Jest**: Primary testing framework
112+
- **ts-jest**: TypeScript support for Jest
113+
- **jsdom**: Browser environment simulation for frontend tests
114+
- Test files use `.test.ts` or `.spec.ts` extensions
115+
- Each package has its own jest.config.js
116+
117+
### Import Patterns
118+
119+
- Use absolute imports with `@cocalc/` prefix for cross-package imports
120+
- Example: `import { cmp } from "@cocalc/util/misc"`
121+
- Type imports: `import type { Foo } from "./bar"`
122+
- Destructure imports when possible
123+
124+
### Development Workflow
125+
126+
1. Changes to TypeScript require compilation (`pnpm build` in relevant package)
127+
2. Database must be running before starting hub
128+
3. Hub coordinates all services and should be restarted after changes
129+
4. Use `pnpm clean && pnpm build-dev` when switching branches or after major changes
130+
131+
# Workflow
132+
133+
- Be sure to build when you're done making a series of code changes
134+
- Prefer running single tests, and not the whole test suite, for performance
135+
136+
## Git Workflow
137+
138+
- Never modify a file when in the `master` or `main` branch
139+
- All changes happen through feature branches, which are pushed as pull requests to GitHub
140+
- When creating a new file, run `git add [filename]` to track the file.
141+
- Prefix git commits with the package and general area. e.g. 'frontend/latex: ...' if it concerns latex editor changes in the packages/frontend/... code.
142+
- When pushing a new branch to Github, track it upstream. e.g. `git push --set-upstream origin feature-foo` for branch "feature-foo".
143+
144+
# Important Instruction Reminders
145+
146+
- Do what has been asked; nothing more, nothing less.
147+
- NEVER create files unless they're absolutely necessary for achieving your goal.
148+
- ALWAYS prefer editing an existing file to creating a new one.
149+
- REFUSE to modify files when the git repository is on the `master` or `main` branch.
150+
- NEVER proactively create documentation files (`*.md`) or README files. Only create documentation files if explicitly requested by the User.
151+
152+
# Ignore
153+
154+
- Ignore files covered by `.gitignore`
155+
- Ignore everything in `node_modules` or `dist` directories
156+
- Ignore all files not tracked by Git, unless they are newly created files

src/packages/next/components/store/add-box.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
Add a cash voucher to your shopping cart.
88
*/
99
import { useState, type JSX } from "react";
10+
import { Alert, Button, Spin } from "antd";
11+
1012
import { CostInputPeriod } from "@cocalc/util/licenses/purchase/types";
1113
import { round2up } from "@cocalc/util/misc";
1214
import { money } from "@cocalc/util/licenses/purchase/utils";
13-
import { Alert, Button, Spin } from "antd";
1415
import { addToCart } from "./add-to-cart";
1516
import { DisplayCost } from "./site-license-cost";
1617
import { periodicCost } from "@cocalc/util/licenses/purchase/compute-cost";
1718
import { decimalDivide } from "@cocalc/util/stripe/calc";
18-
import { LicenseType } from "./types";
19+
20+
import type { LicenseSource } from "@cocalc/util/upgrades/shopping";
1921

2022
export const ADD_STYLE = {
2123
display: "inline-block",
@@ -38,7 +40,7 @@ interface Props {
3840
dedicatedItem?: boolean;
3941
disabled?: boolean;
4042
noAccount: boolean;
41-
type: LicenseType;
43+
source: LicenseSource;
4244
}
4345

4446
export function AddBox({
@@ -50,7 +52,7 @@ export function AddBox({
5052
dedicatedItem = false,
5153
noAccount,
5254
disabled = false,
53-
type,
55+
source,
5456
}: Props) {
5557
if (cost?.input.type == "cash-voucher") {
5658
return null;
@@ -80,7 +82,7 @@ export function AddBox({
8082
message={
8183
<>
8284
{money(round2up(costPer))}{" "}
83-
<b>per {type === "course" ? "student" : "project"}</b>{" "}
85+
<b>per {source === "course" ? "student" : "project"}</b>{" "}
8486
{!!cost.period && cost.period != "range" ? cost.period : ""}
8587
</>
8688
}

src/packages/next/components/store/cart.tsx

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,27 @@ shopping cart experience, so most likely to feel familiar to users and easy
1111
to use.
1212
*/
1313

14+
import { Alert, Button, Checkbox, Popconfirm, Table } from "antd";
15+
import { useRouter } from "next/router";
16+
import { useEffect, useMemo, useState, type JSX } from "react";
17+
1418
import { Icon } from "@cocalc/frontend/components/icon";
19+
import type {
20+
ProductDescription,
21+
ProductType,
22+
} from "@cocalc/util/db-schema/shopping-cart-items";
1523
import { describeQuotaFromInfo } from "@cocalc/util/licenses/describe-quota";
1624
import { CostInputPeriod } from "@cocalc/util/licenses/purchase/types";
25+
import { computeCost } from "@cocalc/util/licenses/store/compute-cost";
1726
import { capitalize, isValidUUID } from "@cocalc/util/misc";
18-
import { Alert, Button, Checkbox, Popconfirm, Table } from "antd";
1927
import A from "components/misc/A";
2028
import Loading from "components/share/loading";
2129
import SiteName from "components/share/site-name";
2230
import apiPost from "lib/api/post";
2331
import useAPI from "lib/hooks/api";
2432
import useIsMounted from "lib/hooks/mounted";
25-
import { useRouter } from "next/router";
26-
import { useEffect, useMemo, useState, type JSX } from "react";
27-
import { computeCost } from "@cocalc/util/licenses/store/compute-cost";
2833
import OtherItems from "./other-items";
2934
import { describeItem, describePeriod, DisplayCost } from "./site-license-cost";
30-
import type {
31-
ProductDescription,
32-
ProductType,
33-
} from "@cocalc/util/db-schema/shopping-cart-items";
3435

3536
export default function ShoppingCart() {
3637
const isMounted = useIsMounted();
@@ -353,9 +354,9 @@ export function DescriptionColumn(props: DCProps) {
353354
const router = useRouter();
354355
const { id, description, style, readOnly } = props;
355356
if (
356-
description.type == "disk" ||
357-
description.type == "vm" ||
358-
description.type == "quota"
357+
description.type === "disk" ||
358+
description.type === "vm" ||
359+
description.type === "quota"
359360
) {
360361
return <DescriptionColumnSiteLicense {...props} />;
361362
} else if (description.type == "cash-voucher") {
@@ -390,9 +391,9 @@ function DescriptionColumnSiteLicense(props: DCProps) {
390391
const { id, cost, description, compact, project_id, readOnly } = props;
391392
if (
392393
!(
393-
description.type == "disk" ||
394-
description.type == "vm" ||
395-
description.type == "quota"
394+
description.type === "disk" ||
395+
description.type === "vm" ||
396+
description.type === "quota"
396397
)
397398
) {
398399
throw Error("BUG -- incorrect typing");
@@ -403,7 +404,7 @@ function DescriptionColumnSiteLicense(props: DCProps) {
403404
return <pre>{JSON.stringify(description, undefined, 2)}</pre>;
404405
}
405406
const { input } = cost;
406-
if (input.type == "cash-voucher") {
407+
if (input.type === "cash-voucher") {
407408
throw Error("incorrect typing");
408409
}
409410

@@ -423,7 +424,7 @@ function DescriptionColumnSiteLicense(props: DCProps) {
423424
}
424425

425426
function editableQuota() {
426-
if (input.type == "cash-voucher") return null;
427+
if (input.type === "cash-voucher") return null;
427428
return (
428429
<div>
429430
<div>{describeQuotaFromInfo(input)}</div>
@@ -433,9 +434,14 @@ function DescriptionColumnSiteLicense(props: DCProps) {
433434
}
434435

435436
// this could rely an the "type" field, but we rather check the data directly
436-
function editPage(): "site-license" | "vouchers" {
437-
if (input.type == "cash-voucher") {
437+
function editPage(): "site-license" | "vouchers" | "course" {
438+
if (input.type === "cash-voucher") {
438439
return "vouchers";
440+
} else if (
441+
description.type === "quota" &&
442+
description.source === "course"
443+
) {
444+
return "course";
439445
}
440446
return "site-license";
441447
}
@@ -451,7 +457,7 @@ function DescriptionColumnSiteLicense(props: DCProps) {
451457
<div style={DESCRIPTION_STYLE}>
452458
<div style={{ marginBottom: "8px" }}>
453459
<b>
454-
{input.subscription == "no"
460+
{input.subscription === "no"
455461
? describePeriod({ quota: input })
456462
: capitalize(input.subscription) + " subscription"}
457463
</b>

src/packages/next/components/store/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ export default function StoreLayout({ page }: Props) {
123123

124124
switch (main) {
125125
case "site-license":
126-
return <SiteLicense noAccount={noAccount} type="license" />;
126+
return <SiteLicense noAccount={noAccount} source="license" />;
127127
case "course":
128-
return <SiteLicense noAccount={noAccount} type="course" />;
128+
return <SiteLicense noAccount={noAccount} source="course" />;
129129
case "cart":
130130
return requireAccount(Cart);
131131
case "checkout":

0 commit comments

Comments
 (0)