Skip to content

Commit 275752a

Browse files
authored
Feature/dap 93 clean up (#172)
New Code Structure ``` domain/ # unchanged — pure types & logic lib/ # unchanged components/ # generic UI: ui/, error-boundary, + move loading-page here features/ degree-audit-app/ # the SPA mounted by entrypoints/degree-audit providers/ # audit-provider, audit-mutations, section-groups, # preferences-provider, course-modal-provider audit-view/ # degree-audit-page, requirement-breakdown, graph, # audit-card, gpa-credit-cards planner-view/ # degree-planner-page, semester-card, semester-dropdowns course-search/ # course-add-modal, CourseSearchPanel, course-card shell/ # navbar, sidebar, degree-completion-donut (shared by both views) catalog/ # DATA ONLY: catalog-db, mappers, department-map, # seed-catalog, scraping/ (no React, no audit imports) audit-scraping/ # unchanged popup/ # unchanged misc/ # unchanged (used to be banner) ``` - Added catalog scripts for refreshing, validating, and generating department mappings. - Added and expanded tests for scraping, audit providers, storage, mutations, and catalog refreshes. - Improved audit scraping behavior and handling of audit data without cached results. - Updated planner drag-and-drop handling. - Updated build, linting, formatting, and CI configuration. - Removed obsolete backend modules, old documentation, unused assets, and outdated example files. Overall this PR was created to ensure a more maintainable codebase.
1 parent a0a7ddf commit 275752a

127 files changed

Lines changed: 23113 additions & 14757 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,25 @@ name: CI
44
on: [push, pull_request]
55

66
jobs:
7+
test:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout repository
11+
uses: actions/checkout@v7
12+
- name: Install bun
13+
uses: oven-sh/setup-bun@v2
14+
- name: Install dependencies
15+
run: bun install
16+
- name: Run tests
17+
run: bun test
18+
719
check:
820
runs-on: ubuntu-latest
921
steps:
1022
- name: Checkout repository
11-
uses: actions/checkout@v3
23+
uses: actions/checkout@v7
1224
- name: Install bun
13-
uses: oven-sh/setup-bun@v1
25+
uses: oven-sh/setup-bun@v2
1426
- name: Install dependencies
1527
run: bun install
1628
- name: Check types
@@ -19,9 +31,9 @@ jobs:
1931
runs-on: ubuntu-latest
2032
steps:
2133
- name: Checkout repository
22-
uses: actions/checkout@v3
34+
uses: actions/checkout@v7
2335
- name: Install bun
24-
uses: oven-sh/setup-bun@v1
36+
uses: oven-sh/setup-bun@v2
2537
- name: Install dependencies
2638
run: bun install
2739
- name: Lint
@@ -31,9 +43,9 @@ jobs:
3143
runs-on: ubuntu-latest
3244
steps:
3345
- name: Checkout repository
34-
uses: actions/checkout@v3
46+
uses: actions/checkout@v7
3547
- name: Install bun
36-
uses: oven-sh/setup-bun@v1
48+
uses: oven-sh/setup-bun@v2
3749
- name: Install dependencies
3850
run: bun install
3951
- name: Format
@@ -43,17 +55,17 @@ jobs:
4355
runs-on: ubuntu-latest
4456
steps:
4557
- name: Checkout repository
46-
uses: actions/checkout@v3
58+
uses: actions/checkout@v7
4759
- name: Install bun
48-
uses: oven-sh/setup-bun@v1
60+
uses: oven-sh/setup-bun@v2
4961
- name: Build extension
5062
run: |
5163
bun install
5264
bun run build
5365
cd .output/chrome-mv3
5466
zip -r ../extension.zip .
5567
- name: Upload artifact
56-
uses: actions/upload-artifact@v4
68+
uses: actions/upload-artifact@v7
5769
with:
5870
name: extension
5971
path: .output/extension.zip

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ stats-*.json
1414
.wxt
1515
web-ext.config.ts
1616
claude.md
17+
18+
# Bun is the package manager; keep npm's lockfile out
19+
package-lock.json
1720
# Editor directories and files
1821
.vscode/*
1922
!.vscode/extensions.json
@@ -27,3 +30,5 @@ claude.md
2730
.claude
2831
*.code-workspace
2932
.claude
33+
34+
docs/

.husky/pre-commit

Lines changed: 0 additions & 1 deletion
This file was deleted.

.prettierignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules
2+
.output
3+
.wxt
4+
bun.lock
5+
package-lock.json
6+
7+
# Test fixtures are raw HTML captures; do not reformat
8+
tests/fixtures/**/*.html

bun.lock

Lines changed: 33 additions & 67 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/error-boundary.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { Component, type ErrorInfo, type ReactNode } from "react";
2+
3+
interface ErrorBoundaryProps {
4+
children: ReactNode;
5+
fallback?: ReactNode;
6+
}
7+
8+
interface ErrorBoundaryState {
9+
hasError: boolean;
10+
error: Error | null;
11+
}
12+
13+
/**
14+
* Single root-level error boundary. Catches render errors (e.g. getCourseById
15+
* throwing on a missing course id) so a bad reference doesn't white-screen the
16+
* whole degree-audit page.
17+
*
18+
* Place one instance at the page root; don't scatter throughout the tree.
19+
*/
20+
export default class ErrorBoundary extends Component<
21+
ErrorBoundaryProps,
22+
ErrorBoundaryState
23+
> {
24+
state: ErrorBoundaryState = { hasError: false, error: null };
25+
26+
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
27+
return { hasError: true, error };
28+
}
29+
30+
componentDidCatch(error: Error, info: ErrorInfo) {
31+
console.error(
32+
"[Degree Audit Plus] Render error caught by ErrorBoundary:",
33+
error,
34+
info,
35+
);
36+
}
37+
38+
handleReset = () => {
39+
this.setState({ hasError: false, error: null });
40+
};
41+
42+
render() {
43+
if (this.state.hasError) {
44+
if (this.props.fallback) return this.props.fallback;
45+
46+
return (
47+
<div className="flex min-h-screen w-full flex-col items-center justify-center gap-4 bg-background px-6 text-center text-text">
48+
<h1 className="text-2xl font-bold text-dap-primary">
49+
Something went wrong
50+
</h1>
51+
<p className="max-w-md text-sm text-dap-gray-light">
52+
An unexpected error occurred while rendering your degree audit.
53+
Re-run your audit from the popup to refresh the data, or click the
54+
button below to try again.
55+
</p>
56+
{this.state.error && (
57+
<pre className="max-w-lg rounded bg-gray-100 px-4 py-2 text-left text-xs text-red-600 dark:bg-gray-800">
58+
{this.state.error.message}
59+
</pre>
60+
)}
61+
<button
62+
onClick={this.handleReset}
63+
className="rounded-md bg-dap-primary px-4 py-2 text-sm font-semibold text-white hover:opacity-90"
64+
>
65+
Try again
66+
</button>
67+
</div>
68+
);
69+
}
70+
71+
return this.props.children;
72+
}
73+
}

entrypoints/degree-audit/components/loading-page.tsx renamed to components/loading-page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { VStack } from "@/entrypoints/components/common/helperdivs";
1+
import { VStack } from "@/components/ui/stack";
22
import { SpinnerIcon } from "@phosphor-icons/react";
33

44
const LoadingPage = () => {

components/ui/button.tsx

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { forwardRef } from "react";
2+
import { cn } from "~/lib/utils";
3+
4+
type ButtonProps = {
5+
color?: "orange" | "white" | "black";
6+
fill?: "solid" | "outline" | "none";
7+
size?: "icon" | "small" | "med" | "large";
8+
} & React.ButtonHTMLAttributes<HTMLButtonElement>;
9+
10+
const styleMap: Record<
11+
NonNullable<ButtonProps["color"]>,
12+
Record<NonNullable<ButtonProps["fill"]>, string>
13+
> = {
14+
orange: {
15+
solid: "bg-dap-primary text-white border-transparent",
16+
outline: "bg-transparent text-dap-primary border-dap-primary",
17+
none: "bg-transparent text-dap-primary border-transparent",
18+
},
19+
white: {
20+
solid: "bg-background text-text border-transparent",
21+
outline: "bg-transparent text-white border-white",
22+
none: "bg-transparent text-white border-transparent",
23+
},
24+
black: {
25+
solid: "bg-text text-background border-transparent",
26+
outline: "bg-transparent text-text border-text",
27+
none: "bg-transparent text-text border-transparent",
28+
},
29+
};
30+
31+
const sizeMap: Record<NonNullable<ButtonProps["size"]>, string> = {
32+
icon: "w-8 h-8 p-0",
33+
small: "px-2 py-1 text-sm",
34+
med: "px-4 py-2 text-base",
35+
large: "px-6 py-3 text-lg",
36+
};
37+
const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
38+
const {
39+
color = "orange",
40+
fill = "solid",
41+
size = null,
42+
className,
43+
...rest
44+
} = props;
45+
46+
return (
47+
<button
48+
ref={ref}
49+
className={cn(
50+
"px-4 py-2 rounded-lg whitespace-nowrap w-fit flex flex-row items-center justify-center gap-2 border hover:opacity-80 cursor-pointer transition-all duration-300",
51+
styleMap[color][fill],
52+
size && sizeMap[size],
53+
className,
54+
)}
55+
{...rest}
56+
>
57+
{rest.children}
58+
</button>
59+
);
60+
});
61+
Button.displayName = "Button";
62+
63+
export const IconButton = forwardRef<
64+
HTMLButtonElement,
65+
Omit<ButtonProps, "children"> & { icon: React.ReactNode; label?: string }
66+
>((props, ref) => {
67+
return (
68+
<Button ref={ref} {...props}>
69+
{props.icon}
70+
{props.label && <span className="text-sm">{props.label}</span>}
71+
</Button>
72+
);
73+
});
74+
IconButton.displayName = "IconButton";
75+
76+
export default Button;
File renamed without changes.

entrypoints/components/common/dropdown.tsx renamed to components/ui/dropdown.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import React, {
99
} from "react";
1010
import { cn } from "~/lib/utils";
1111
import Container from "./container";
12-
import { HStack, VStack } from "./helperdivs";
12+
import { HStack, VStack } from "./stack";
1313

1414
// Context to share dropdown state with sub-components
1515
type DropdownContextType = {
@@ -130,8 +130,4 @@ const Dropdown = forwardRef<
130130

131131
Dropdown.displayName = "Dropdown";
132132

133-
// Attach sub-components to main component
134-
(Dropdown as any).Header = DropdownHeader;
135-
(Dropdown as any).Content = DropdownContent;
136-
137133
export default Dropdown;

0 commit comments

Comments
 (0)