Yassine Mhirsi commited on
Commit
cbf89ee
·
1 Parent(s): 3d7ddc5
.cursor/rules/rules.mdc ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ alwaysApply: true
3
+ ---
4
+
5
+ # NLP IBM Debater - Cursor Rules
6
+
7
+ This is a React + TypeScript project using Create React App, Tailwind CSS, and a modular feature-first architecture.
8
+
9
+ ## File Extensions & TypeScript
10
+
11
+ - **`.tsx`** - Use for React components (components, pages, layouts)
12
+ - **`.ts`** - Use for non-JSX files (hooks, utils, types, services)
13
+ - **`.js`** - Only for config files (index.js, config files)
14
+ - **Always type everything**: props, functions, API responses, hook returns
15
+
16
+ ## Project Structure
17
+
18
+ ```
19
+ src/app/
20
+ ├── App.tsx # Entry composition
21
+ ├── layouts/ # Layout components (.tsx)
22
+ ├── pages/ # Page components (.tsx)
23
+ ├── components/ # Reusable UI (.tsx)
24
+ │ └── common/ # Common components (Loading, ErrorBoundary)
25
+ ├── hooks/ # Custom hooks (.ts)
26
+ ├── services/ # API services (.ts)
27
+ ├── types/ # TypeScript types (.ts)
28
+ ├── utils/ # Utility functions (.ts)
29
+ └── constants/ # App constants (.ts)
30
+ ```
31
+
32
+ ## Code Patterns
33
+
34
+ ### Components
35
+ - Use functional components with `React.FC<PropsType>`
36
+ - Always type props with interfaces or types
37
+ - Use Tailwind CSS for styling (avoid custom CSS files)
38
+ - Keep components presentational - pass data via props
39
+
40
+ ```typescript
41
+ type MyComponentProps = {
42
+ title: string;
43
+ count?: number;
44
+ };
45
+
46
+ const MyComponent: React.FC<MyComponentProps> = ({ title, count = 0 }) => {
47
+ return <div>{title}: {count}</div>;
48
+ };
49
+ ```
50
+
51
+ ### API Calls
52
+ - Use `api-wrapper.ts` for direct API calls
53
+ - Use `useApi` hook for components needing loading/error states
54
+ - Always type API responses
55
+
56
+ ```typescript
57
+ // Direct API call
58
+ import api from '../services/api-wrapper';
59
+ const data = await api.get<User[]>('/api/users');
60
+
61
+ // With hook
62
+ import { useApi } from '../hooks/useApi';
63
+ const { data, loading, error } = useApi<User[]>('/api/users');
64
+ ```
65
+
66
+ ### Types
67
+ - Add types to `src/app/types/` and export from `index.ts`
68
+ - Use descriptive type names
69
+ - Export types for reuse
70
+
71
+ ```typescript
72
+ // src/app/types/debater.types.ts
73
+ export type Debate = {
74
+ id: number;
75
+ topic: string;
76
+ arguments: Argument[];
77
+ };
78
+ ```
79
+
80
+ ### Constants
81
+ - Add constants to `src/app/constants/index.ts`
82
+ - Use `API_ENDPOINTS` for API paths
83
+ - Use `APP_CONFIG` for app configuration
84
+ - Use `UI` for UI-related constants
85
+
86
+ ### Utils
87
+ - Add utility functions to `src/app/utils/index.ts`
88
+ - Keep functions pure and typed
89
+ - Export for reuse
90
+
91
+ ## Conventions
92
+
93
+ 1. **Imports**: Use relative paths from `src/`
94
+ 2. **Styling**: Tailwind-first, avoid custom CSS
95
+ 3. **Error Handling**: Use ErrorBoundary for React errors, try/catch for API errors
96
+ 4. **Loading States**: Use `Loading` component from `components/common/Loading`
97
+ 5. **Environment Variables**: All must start with `REACT_APP_` prefix
98
+ 6. **Testing**: Use React Testing Library, co-locate tests
99
+
100
+ ## What NOT to Do
101
+
102
+ - ❌ Don't use class components (except ErrorBoundary)
103
+ - ❌ Don't use `.jsx` - use `.tsx` for components
104
+ - ❌ Don't use raw `fetch` - use `api-wrapper.ts`
105
+ - ❌ Don't create custom CSS files - use Tailwind
106
+ - ❌ Don't commit `.env*` files (except `.env.example`)
107
+ - ❌ Don't skip TypeScript types
108
+
109
+ ## When Adding New Features
110
+
111
+ 1. **New Page**: Create in `src/app/pages/` (`.tsx`), wire via `App.tsx`
112
+ 2. **New Component**: Create in `src/app/components/` (`.tsx`), type props
113
+ 3. **New API Endpoint**: Add to `API_ENDPOINTS` in constants, use `api-wrapper.ts`
114
+ 4. **New Type**: Add to `src/app/types/`, export from `index.ts`
115
+ 5. **New Hook**: Create in `src/app/hooks/` (`.ts`), type return values
116
+ 6. **New Utility**: Add to `src/app/utils/index.ts`, keep pure and typed
117
+
118
+ ## Quality Checks
119
+
120
+ - Run `npm run build` to verify TypeScript compilation
121
+ - Run `npm test` before committing
122
+ - Ensure all props are typed
123
+ - Ensure all API calls use typed responses
124
+ - Follow existing code patterns and structure
.env.example ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Environment Variables Template
2
+ #
3
+ # Copy this file to create your local environment files:
4
+ # - For development: cp .env.example .env.development.local
5
+ # - For production: cp .env.example .env.production.local
6
+ #
7
+ # All .env files are gitignored for security.
8
+ # Update this template when adding new required environment variables.
9
+
10
+ # API Configuration
11
+ REACT_APP_API_BASE_URL=http://localhost:4000
12
+
13
+ # Add other environment variables below (must start with REACT_APP_)
14
+ # REACT_APP_ANOTHER_VAR=value
15
+
.gitignore CHANGED
@@ -11,13 +11,79 @@
11
  # production
12
  /build
13
 
14
- # misc
15
- .DS_Store
16
  .env.local
 
17
  .env.development.local
 
18
  .env.test.local
 
19
  .env.production.local
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  npm-debug.log*
22
  yarn-debug.log*
23
  yarn-error.log*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  # production
12
  /build
13
 
14
+ # environment variables (all .env files ignored - use .env.example as template)
15
+ .env
16
  .env.local
17
+ .env.development
18
  .env.development.local
19
+ .env.test
20
  .env.test.local
21
+ .env.production
22
  .env.production.local
23
 
24
+ # misc
25
+ .DS_Store
26
+ .DS_Store?
27
+ ._*
28
+ .Spotlight-V100
29
+ .Trashes
30
+ ehthumbs.db
31
+ Thumbs.db
32
+
33
+ # IDE / Editor
34
+ .vscode/
35
+ .idea/
36
+ *.swp
37
+ *.swo
38
+ *~
39
+ .project
40
+ .classpath
41
+ .settings/
42
+ *.sublime-project
43
+ *.sublime-workspace
44
+
45
+ # Logs
46
+ logs
47
+ *.log
48
  npm-debug.log*
49
  yarn-debug.log*
50
  yarn-error.log*
51
+ pnpm-debug.log*
52
+ lerna-debug.log*
53
+
54
+ # Runtime data
55
+ pids
56
+ *.pid
57
+ *.seed
58
+ *.pid.lock
59
+
60
+ # Optional npm cache directory
61
+ .npm
62
+
63
+ # Optional eslint cache
64
+ .eslintcache
65
+
66
+ # Optional REPL history
67
+ .node_repl_history
68
+
69
+ # Output of 'npm pack'
70
+ *.tgz
71
+
72
+ # Yarn Integrity file
73
+ .yarn-integrity
74
+
75
+ # parcel-bundler cache
76
+ .cache
77
+ .parcel-cache
78
+
79
+ # Next.js (if ever migrated)
80
+ .next
81
+ out
82
+
83
+ # Nuxt.js (if ever migrated)
84
+ .nuxt
85
+ dist
86
+
87
+ # Temporary folders
88
+ tmp/
89
+ temp/
LLM_GUIDE.md ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # LLM Guide: NLP-IBM-Debater Workspace
2
+
3
+ This repository is a React + TypeScript (Create React App) workspace prepared with Tailwind CSS and a modular app layout. Use this guide as the single source of truth when making automated or AI-assisted changes.
4
+
5
+ ## Project map
6
+
7
+ - `src/app/App.tsx` — entry composition (TypeScript).
8
+ - `src/app/layouts/MainLayout.tsx` — basic layout wrapper (TypeScript).
9
+ - `src/app/pages/` — page components (use `.tsx` extension).
10
+ - `src/app/components/` — reusable UI pieces (common/navigation, use `.tsx` extension).
11
+ - `common/ErrorBoundary.tsx` — error boundary component (class component, required by React).
12
+ - `common/Loading.tsx` — loading spinner component.
13
+ - `src/app/services/api-wrapper.ts` — centralized API client with fetch wrapper (GET/POST/PUT/PATCH/DELETE).
14
+ - `src/app/hooks/` — custom React hooks (use `.ts` extension).
15
+ - `useApi.ts` — hook for API calls with loading/error states.
16
+ - `src/app/types/` — TypeScript type definitions (use `.ts` extension).
17
+ - `api.types.ts` — API-related types.
18
+ - `index.ts` — central export point for all types.
19
+ - `src/app/utils/` — utility functions (use `.ts` extension, debounce, formatError, etc.).
20
+ - `src/app/constants/` — app-wide constants (use `.ts` extension, API endpoints, config).
21
+ - `src/index.js` — CRA entry point mounting `App` with ErrorBoundary.
22
+ - `tailwind.config.js` & `postcss.config.js` — Tailwind setup.
23
+ - `.env.example` — environment variables template (all `.env*` files are gitignored).
24
+
25
+ ## Conventions
26
+
27
+ - **File Extensions**:
28
+ - Use `.tsx` for React components (components, pages, layouts)
29
+ - Use `.ts` for non-JSX TypeScript files (hooks, utils, types, services)
30
+ - Use `.js` only for config files (index.js, config files)
31
+ - **TypeScript**: This project uses TypeScript for type safety. Always type your props, functions, and API responses.
32
+ - Prefer feature-first folders under `src/app` (`components`, `pages`, `layouts`, `data`, `hooks`, `services` as needed).
33
+ - Styling is Tailwind-first; avoid ad-hoc CSS files unless adding global tokens.
34
+ - Keep components presentational and pass data via props; co-locate tests next to features or under `__tests__`.
35
+ - Use functional components and hooks; avoid class components (except ErrorBoundary which requires a class).
36
+ - Keep imports relative to `src/` (CRA default) and prefer absolute paths only if `NODE_PATH`/aliases are introduced.
37
+
38
+ ## Commands
39
+
40
+ - Install deps: `npm install`
41
+ - Start dev server: `npm start` (loads `.env.development`)
42
+ - Build for prod: `npm run build` (loads `.env.production`)
43
+ - Run tests: `npm test`
44
+
45
+ ## Environment Variables
46
+
47
+ - **`.env.example`** — Template showing required variables (committed to git)
48
+ - **All `.env*` files** — Gitignored for security (create from `.env.example`)
49
+
50
+ **Important**: All environment variables exposed to the browser must start with `REACT_APP_` prefix.
51
+
52
+ **Setup**:
53
+ 1. Copy `.env.example` to create your local env files:
54
+ - Development: `cp .env.example .env.development.local`
55
+ - Production: `cp .env.example .env.production.local`
56
+ 2. Update the values in your local `.env.*.local` files
57
+
58
+ Current variables:
59
+ - `REACT_APP_API_BASE_URL` — API base URL (defaults to `http://localhost:4000` if not set)
60
+
61
+ To add new variables:
62
+ 1. Add to `.env.example` as documentation
63
+ 2. Update your local `.env.*.local` files
64
+ 3. Access via `process.env.REACT_APP_YOUR_VAR`
65
+
66
+ ## Patterns to follow
67
+
68
+ - Add new UI to `src/app/pages` (use `.tsx` extension) and wire via `App.tsx`.
69
+ - Reuse `MainLayout` for consistent shell elements.
70
+ - Keep static strings in `src/app/data` for reuse/testing.
71
+ - **API calls**:
72
+ - Use `src/app/services/api-wrapper.ts` for direct API calls: `api.get()`, `api.post()`, etc.
73
+ - Use `useApi` hook from `src/app/hooks/useApi.ts` for components that need loading/error states.
74
+ - **Types**: Add new TypeScript types to `src/app/types/` (use `.ts` extension) and export from `index.ts`.
75
+ - **Constants**: Add app-wide constants to `src/app/constants/index.ts`.
76
+ - **Utils**: Add reusable utility functions to `src/app/utils/index.ts`.
77
+ - **Component Props**: Always type your component props using TypeScript interfaces or types.
78
+ - When adding new services, create `src/app/services/*` (use `.ts` extension) and keep fetchers pure; inject into components via hooks or props.
79
+
80
+ ## Quality and safety
81
+
82
+ - Use React Testing Library for behavior-first tests.
83
+ - Avoid editing generated configs unless necessary; prefer small, reviewable diffs.
84
+ - Document non-obvious decisions inline with concise comments.
85
+
86
+ ## API Service Usage
87
+
88
+ ### Direct API calls
89
+
90
+ The `api-wrapper.ts` service provides a typed, centralized way to make HTTP requests:
91
+
92
+ ```typescript
93
+ import api from '../services/api-wrapper';
94
+
95
+ // GET request
96
+ const data = await api.get<User[]>('/users');
97
+
98
+ // POST request
99
+ const newUser = await api.post<User, CreateUserDto>('/users', { name: 'John' });
100
+
101
+ // With error handling
102
+ try {
103
+ const result = await api.get('/endpoint');
104
+ } catch (error) {
105
+ // error is typed as ApiError with status, message, details
106
+ console.error(error.status, error.message);
107
+ }
108
+ ```
109
+
110
+ ### Using the useApi hook
111
+
112
+ For components that need loading and error states:
113
+
114
+ ```typescript
115
+ import { useApi } from '../hooks/useApi';
116
+ import Loading from '../components/common/Loading';
117
+ import type { User } from '../types';
118
+
119
+ const MyComponent: React.FC = () => {
120
+ const { data, loading, error, refetch } = useApi<User[]>('/api/users');
121
+
122
+ if (loading) return <Loading />;
123
+ if (error) return <div>Error: {error.message}</div>;
124
+
125
+ return <div>{/* render data */}</div>;
126
+ };
127
+ ```
128
+
129
+ The service automatically:
130
+ - Uses `REACT_APP_API_BASE_URL` from environment variables
131
+ - Sets JSON content-type headers
132
+ - Handles JSON parsing
133
+ - Throws typed errors for non-OK responses
134
+ - Supports AbortSignal for request cancellation
135
+
136
+ ## TypeScript Guidelines
137
+
138
+ - **Components**: Always type props using interfaces or types
139
+ ```typescript
140
+ type MyComponentProps = {
141
+ title: string;
142
+ count?: number;
143
+ };
144
+
145
+ const MyComponent: React.FC<MyComponentProps> = ({ title, count = 0 }) => {
146
+ // ...
147
+ };
148
+ ```
149
+
150
+ - **API Responses**: Type your API responses
151
+ ```typescript
152
+ type User = {
153
+ id: number;
154
+ name: string;
155
+ };
156
+
157
+ const users = await api.get<User[]>('/api/users');
158
+ ```
159
+
160
+ - **Hooks**: Type hook return values and parameters
161
+ ```typescript
162
+ const { data, loading } = useApi<Debate[]>('/api/debates');
163
+ ```
164
+
165
+ ## How to help
166
+
167
+ - Before large refactors, note intent and file targets in the PR description.
168
+ - After code edits, run tests or `npm run build` to verify TypeScript compilation.
169
+ - When adding API endpoints, use the `api-wrapper.ts` service instead of raw `fetch`.
170
+ - Always use TypeScript types for props, API responses, and function parameters.
171
+ - Keep this guide updated when changing structure, commands, or adding new services.
172
+
README.md CHANGED
@@ -1,82 +1,32 @@
1
- ---
2
- title: NLP IBM Debater
3
- emoji: 🐠
4
- colorFrom: indigo
5
- colorTo: red
6
- sdk: static
7
- pinned: false
8
- app_build_command: npm run build
9
- app_file: build/index.html
10
- license: mit
11
- ---
12
 
13
- # Getting Started with Create React App
14
 
15
- This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
16
 
17
- ## Available Scripts
 
 
 
 
 
 
18
 
19
- In the project directory, you can run:
20
 
21
- ### `npm start`
 
 
22
 
23
- Runs the app in the development mode.\
24
- Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
25
 
26
- The page will reload when you make changes.\
27
- You may also see any lint errors in the console.
28
 
29
- ### `npm test`
30
 
31
- Launches the test runner in the interactive watch mode.\
32
- See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
 
 
33
 
34
- ### `npm run build`
35
-
36
- Builds the app for production to the `build` folder.\
37
- It correctly bundles React in production mode and optimizes the build for the best performance.
38
-
39
- The build is minified and the filenames include the hashes.\
40
- Your app is ready to be deployed!
41
-
42
- See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
43
-
44
- ### `npm run eject`
45
-
46
- **Note: this is a one-way operation. Once you `eject`, you can't go back!**
47
-
48
- If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
49
-
50
- Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
51
-
52
- You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
53
-
54
- ## Learn More
55
-
56
- You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
57
-
58
- To learn React, check out the [React documentation](https://reactjs.org/).
59
-
60
- ### Code Splitting
61
-
62
- This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
63
-
64
- ### Analyzing the Bundle Size
65
-
66
- This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
67
-
68
- ### Making a Progressive Web App
69
-
70
- This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
71
-
72
- ### Advanced Configuration
73
-
74
- This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
75
-
76
- ### Deployment
77
-
78
- This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
79
-
80
- ### `npm run build` fails to minify
81
-
82
- This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
 
1
+ # NLP IBM Debater — React + Tailwind Workspace
 
 
 
 
 
 
 
 
 
 
2
 
3
+ An opinionated Create React App setup designed for fast iteration on NLP experiences. Tailwind CSS is wired in, and the app structure is organized for feature-first development.
4
 
5
+ ## Project structure
6
 
7
+ - `src/app/App.jsx` — root composition.
8
+ - `src/app/layouts/MainLayout.jsx` — shared shell with navigation and footer.
9
+ - `src/app/pages/HomePage.jsx` — starter page showing layout and cards.
10
+ - `src/app/components/` — reusable UI (navigation/common).
11
+ - `src/app/data/` — UI copy and data stubs.
12
+ - `LLM_GUIDE.md` — instructions for AI collaborators.
13
+ - `tailwind.config.js` and `postcss.config.js` — Tailwind setup.
14
 
15
+ ## Scripts
16
 
17
+ - `npm start` — run the dev server.
18
+ - `npm test` — run tests in watch mode.
19
+ - `npm run build` — production build.
20
 
21
+ ## Tailwind usage
 
22
 
23
+ Tailwind is configured via `tailwind.config.js`. Global styles live in `src/index.css` with Tailwind directives. Use utility classes for new UI and extend the config when adding design tokens.
 
24
 
25
+ ## Adding features
26
 
27
+ 1. Create a page in `src/app/pages` and wire it through `App.jsx`.
28
+ 2. Add shared UI to `src/app/components`.
29
+ 3. Store static copy or mock data in `src/app/data`.
30
+ 4. Write behavioral tests with React Testing Library.
31
 
32
+ For more collaboration guidance, see `LLM_GUIDE.md`.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json CHANGED
@@ -1,5 +1,5 @@
1
  {
2
- "name": "react-template",
3
  "version": "0.1.0",
4
  "private": true,
5
  "dependencies": {
@@ -12,6 +12,11 @@
12
  "react-scripts": "5.0.1",
13
  "web-vitals": "^2.1.4"
14
  },
 
 
 
 
 
15
  "scripts": {
16
  "start": "react-scripts start",
17
  "build": "react-scripts build",
 
1
  {
2
+ "name": "nlp-ibm-debater",
3
  "version": "0.1.0",
4
  "private": true,
5
  "dependencies": {
 
12
  "react-scripts": "5.0.1",
13
  "web-vitals": "^2.1.4"
14
  },
15
+ "devDependencies": {
16
+ "autoprefixer": "^10.4.22",
17
+ "postcss": "^8.5.6",
18
+ "tailwindcss": "^3.4.18"
19
+ },
20
  "scripts": {
21
  "start": "react-scripts start",
22
  "build": "react-scripts build",
postcss.config.js ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
7
+
src/App.css DELETED
@@ -1,38 +0,0 @@
1
- .App {
2
- text-align: center;
3
- }
4
-
5
- .App-logo {
6
- height: 40vmin;
7
- pointer-events: none;
8
- }
9
-
10
- @media (prefers-reduced-motion: no-preference) {
11
- .App-logo {
12
- animation: App-logo-spin infinite 20s linear;
13
- }
14
- }
15
-
16
- .App-header {
17
- background-color: #282c34;
18
- min-height: 100vh;
19
- display: flex;
20
- flex-direction: column;
21
- align-items: center;
22
- justify-content: center;
23
- font-size: calc(10px + 2vmin);
24
- color: white;
25
- }
26
-
27
- .App-link {
28
- color: #61dafb;
29
- }
30
-
31
- @keyframes App-logo-spin {
32
- from {
33
- transform: rotate(0deg);
34
- }
35
- to {
36
- transform: rotate(360deg);
37
- }
38
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/App.js DELETED
@@ -1,25 +0,0 @@
1
- import logo from './logo.svg';
2
- import './App.css';
3
-
4
- function App() {
5
- return (
6
- <div className="App">
7
- <header className="App-header">
8
- <img src={logo} className="App-logo" alt="logo" />
9
- <p>
10
- Edit <code>src/App.js</code> and save to reload.
11
- </p>
12
- <a
13
- className="App-link"
14
- href="https://reactjs.org"
15
- target="_blank"
16
- rel="noopener noreferrer"
17
- >
18
- Learn React
19
- </a>
20
- </header>
21
- </div>
22
- );
23
- }
24
-
25
- export default App;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/App.test.js CHANGED
@@ -1,8 +1,6 @@
1
- import { render, screen } from '@testing-library/react';
2
- import App from './App';
3
 
4
- test('renders learn react link', () => {
5
  render(<App />);
6
- const linkElement = screen.getByText(/learn react/i);
7
- expect(linkElement).toBeInTheDocument();
8
  });
 
1
+ import { render } from '@testing-library/react';
2
+ import App from './app/App';
3
 
4
+ test('renders app without crashing', () => {
5
  render(<App />);
 
 
6
  });
src/app/App.tsx ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import MainLayout from './layouts/MainLayout.tsx';
3
+
4
+ const App: React.FC = () => (
5
+ <MainLayout>
6
+ <div className="container mx-auto px-4 py-8">
7
+ {/* Your content here */}
8
+ </div>
9
+ </MainLayout>
10
+ );
11
+
12
+ export default App;
13
+
src/app/components/common/ErrorBoundary.tsx ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { Component, ErrorInfo, ReactNode } from 'react';
2
+
3
+ type Props = {
4
+ children: ReactNode;
5
+ };
6
+
7
+ type State = {
8
+ hasError: boolean;
9
+ error: Error | null;
10
+ };
11
+
12
+ /**
13
+ * Error Boundary component - catches React errors and displays fallback UI
14
+ * Note: Error boundaries must be class components (React limitation)
15
+ */
16
+ class ErrorBoundary extends Component<Props, State> {
17
+ constructor(props: Props) {
18
+ super(props);
19
+ this.state = { hasError: false, error: null };
20
+ }
21
+
22
+ static getDerivedStateFromError(error: Error): State {
23
+ return { hasError: true, error };
24
+ }
25
+
26
+ componentDidCatch(error: Error, errorInfo: ErrorInfo) {
27
+ console.error('ErrorBoundary caught an error:', error, errorInfo);
28
+ }
29
+
30
+ render() {
31
+ if (this.state.hasError) {
32
+ return (
33
+ <div className="flex min-h-screen items-center justify-center bg-gray-50 px-4">
34
+ <div className="text-center">
35
+ <h1 className="mb-4 text-2xl font-bold text-gray-900">
36
+ Something went wrong
37
+ </h1>
38
+ <p className="mb-4 text-gray-600">
39
+ {this.state.error?.message || 'An unexpected error occurred'}
40
+ </p>
41
+ <button
42
+ onClick={() => {
43
+ this.setState({ hasError: false, error: null });
44
+ window.location.reload();
45
+ }}
46
+ className="rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700"
47
+ >
48
+ Reload Page
49
+ </button>
50
+ </div>
51
+ </div>
52
+ );
53
+ }
54
+
55
+ return this.props.children;
56
+ }
57
+ }
58
+
59
+ export default ErrorBoundary;
60
+
src/app/components/common/Loading.tsx ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+
3
+ type LoadingProps = {
4
+ size?: 'sm' | 'md' | 'lg';
5
+ text?: string;
6
+ };
7
+
8
+ /**
9
+ * Loading spinner component
10
+ */
11
+ const Loading: React.FC<LoadingProps> = ({ size = 'md', text }) => {
12
+ const sizeClasses = {
13
+ sm: 'h-4 w-4',
14
+ md: 'h-8 w-8',
15
+ lg: 'h-12 w-12',
16
+ };
17
+
18
+ return (
19
+ <div className="flex flex-col items-center justify-center p-4">
20
+ <div
21
+ className={`${sizeClasses[size]} animate-spin rounded-full border-4 border-gray-200 border-t-blue-600`}
22
+ role="status"
23
+ aria-label="Loading"
24
+ />
25
+ {text && <p className="mt-2 text-sm text-gray-600">{text}</p>}
26
+ </div>
27
+ );
28
+ };
29
+
30
+ export default Loading;
31
+
src/app/constants/index.ts ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Application-wide constants
3
+ */
4
+
5
+ // API Endpoints (add your endpoints here as you build)
6
+ export const API_ENDPOINTS = {
7
+
8
+ } as const;
9
+
10
+ // App configuration
11
+ export const APP_CONFIG = {
12
+ APP_NAME: 'NLP IBM Debater',
13
+ VERSION: '0.1.0',
14
+ } as const;
15
+
16
+ // UI Constants
17
+ export const UI = {
18
+ DEBOUNCE_DELAY: 300, // ms
19
+ ANIMATION_DURATION: 200, // ms
20
+ } as const;
21
+
src/app/hooks/index.ts ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Central export point for all custom hooks
3
+ */
4
+
5
+ export { default as useApi } from './useApi';
6
+ export { useApi as useApiHook } from './useApi';
7
+
src/app/hooks/useApi.ts ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useEffect } from 'react';
2
+ import api from '../services/api-wrapper';
3
+ import type { ApiError } from '../types/api.types';
4
+
5
+ type UseApiState<T> = {
6
+ data: T | null;
7
+ loading: boolean;
8
+ error: ApiError | null;
9
+ };
10
+
11
+ type UseApiOptions = {
12
+ immediate?: boolean; // Whether to fetch immediately on mount
13
+ };
14
+
15
+ /**
16
+ * Custom hook for making API calls with loading and error states
17
+ *
18
+ * @example
19
+ * const { data, loading, error, execute } = useApi<User[]>('/api/users');
20
+ *
21
+ * // Or with manual trigger
22
+ * const { data, loading, error, execute } = useApi<User[]>('/api/users', { immediate: false });
23
+ * execute(); // Call manually
24
+ */
25
+ export function useApi<T>(
26
+ url: string,
27
+ options: UseApiOptions = { immediate: true }
28
+ ): UseApiState<T> & { execute: () => Promise<void>; refetch: () => Promise<void> } {
29
+ const [state, setState] = useState<UseApiState<T>>({
30
+ data: null,
31
+ loading: options.immediate ?? true,
32
+ error: null,
33
+ });
34
+
35
+ const execute = async () => {
36
+ setState((prev) => ({ ...prev, loading: true, error: null }));
37
+ try {
38
+ const data = await api.get<T>(url);
39
+ setState({ data, loading: false, error: null });
40
+ } catch (err) {
41
+ setState({
42
+ data: null,
43
+ loading: false,
44
+ error: err as ApiError,
45
+ });
46
+ }
47
+ };
48
+
49
+ useEffect(() => {
50
+ if (options.immediate !== false) {
51
+ execute();
52
+ }
53
+ // eslint-disable-next-line react-hooks/exhaustive-deps
54
+ }, [url]);
55
+
56
+ return {
57
+ ...state,
58
+ execute,
59
+ refetch: execute,
60
+ };
61
+ }
62
+
63
+ export default useApi;
64
+
src/app/layouts/MainLayout.tsx ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+
3
+ type MainLayoutProps = {
4
+ children: React.ReactNode;
5
+ };
6
+
7
+ const MainLayout: React.FC<MainLayoutProps> = ({ children }) => (
8
+ <div className="min-h-screen">
9
+ {children}
10
+ </div>
11
+ );
12
+
13
+ export default MainLayout;
14
+
src/app/services/api-wrapper.ts ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { ApiRequestOptions, ApiError } from '../types/api.types';
2
+
3
+ const DEFAULT_HEADERS: HeadersInit = {
4
+ 'Content-Type': 'application/json',
5
+ };
6
+
7
+ const BASE_URL =
8
+ process.env.REACT_APP_API_BASE_URL?.replace(/\/$/, '');
9
+
10
+ export type { ApiRequestOptions, ApiError };
11
+
12
+ export async function apiRequest<TResponse = unknown, TBody = unknown>({
13
+ path,
14
+ method = 'GET',
15
+ body,
16
+ headers,
17
+ signal,
18
+ }: ApiRequestOptions<TBody>): Promise<TResponse> {
19
+ const url = `${BASE_URL}${path.startsWith('/') ? '' : '/'}${path}`;
20
+
21
+ const response = await fetch(url, {
22
+ method,
23
+ headers: {
24
+ ...DEFAULT_HEADERS,
25
+ ...(headers ?? {}),
26
+ },
27
+ body: body ? JSON.stringify(body) : undefined,
28
+ signal,
29
+ });
30
+
31
+ const contentType = response.headers.get('content-type');
32
+ const isJson = contentType?.includes('application/json');
33
+ const payload = isJson ? await response.json().catch(() => undefined) : undefined;
34
+
35
+ if (!response.ok) {
36
+ const error: ApiError = {
37
+ status: response.status,
38
+ message:
39
+ (payload as { message?: string })?.message ||
40
+ response.statusText ||
41
+ 'Request failed',
42
+ details: payload,
43
+ };
44
+ throw error;
45
+ }
46
+
47
+ return payload as TResponse;
48
+ }
49
+
50
+ export const api = {
51
+ get: <TResponse>(path: string, init?: Omit<ApiRequestOptions, 'path' | 'method'>) =>
52
+ apiRequest<TResponse>({ path, method: 'GET', ...init }),
53
+ post: <TResponse, TBody = unknown>(
54
+ path: string,
55
+ body?: TBody,
56
+ init?: Omit<ApiRequestOptions<TBody>, 'path' | 'method' | 'body'>,
57
+ ) => apiRequest<TResponse, TBody>({ path, method: 'POST', body, ...init }),
58
+ put: <TResponse, TBody = unknown>(
59
+ path: string,
60
+ body?: TBody,
61
+ init?: Omit<ApiRequestOptions<TBody>, 'path' | 'method' | 'body'>,
62
+ ) => apiRequest<TResponse, TBody>({ path, method: 'PUT', body, ...init }),
63
+ patch: <TResponse, TBody = unknown>(
64
+ path: string,
65
+ body?: TBody,
66
+ init?: Omit<ApiRequestOptions<TBody>, 'path' | 'method' | 'body'>,
67
+ ) => apiRequest<TResponse, TBody>({ path, method: 'PATCH', body, ...init }),
68
+ delete: <TResponse>(path: string, init?: Omit<ApiRequestOptions, 'path' | 'method'>) =>
69
+ apiRequest<TResponse>({ path, method: 'DELETE', ...init }),
70
+ };
71
+
72
+ export default api;
73
+
src/app/types/api.types.ts ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * API-related TypeScript types and interfaces
3
+ */
4
+
5
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
6
+
7
+ export type ApiRequestOptions<TBody = unknown> = {
8
+ path: string;
9
+ method?: HttpMethod;
10
+ body?: TBody;
11
+ headers?: HeadersInit;
12
+ signal?: AbortSignal;
13
+ };
14
+
15
+ export type ApiError = {
16
+ status: number;
17
+ message: string;
18
+ details?: unknown;
19
+ };
20
+
src/app/types/index.ts ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Central export point for all types
3
+ * Import types from here: import { SomeType } from '../types';
4
+ */
5
+
6
+ export * from './api.types';
7
+
src/app/utils/index.ts ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Utility functions and helpers
3
+ */
4
+
5
+ /**
6
+ * Debounce function - delays execution until after wait time
7
+ */
8
+ export function debounce<T extends (...args: any[]) => any>(
9
+ func: T,
10
+ wait: number
11
+ ): (...args: Parameters<T>) => void {
12
+ let timeout: NodeJS.Timeout | null = null;
13
+ return function executedFunction(...args: Parameters<T>) {
14
+ const later = () => {
15
+ timeout = null;
16
+ func(...args);
17
+ };
18
+ if (timeout) clearTimeout(timeout);
19
+ timeout = setTimeout(later, wait);
20
+ };
21
+ }
22
+
23
+ /**
24
+ * Format error message from API error or string
25
+ */
26
+ export function formatError(error: unknown): string {
27
+ if (typeof error === 'string') return error;
28
+ if (error && typeof error === 'object' && 'message' in error) {
29
+ return String(error.message);
30
+ }
31
+ return 'An unexpected error occurred';
32
+ }
33
+
34
+ /**
35
+ * Sleep/delay utility
36
+ */
37
+ export function sleep(ms: number): Promise<void> {
38
+ return new Promise((resolve) => setTimeout(resolve, ms));
39
+ }
40
+
41
+ /**
42
+ * Check if value is empty (null, undefined, empty string, empty array, empty object)
43
+ */
44
+ export function isEmpty(value: unknown): boolean {
45
+ if (value == null) return true;
46
+ if (typeof value === 'string') return value.trim().length === 0;
47
+ if (Array.isArray(value)) return value.length === 0;
48
+ if (typeof value === 'object') return Object.keys(value).length === 0;
49
+ return false;
50
+ }
51
+
src/index.css CHANGED
@@ -1,13 +1,19 @@
1
- body {
2
- margin: 0;
3
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4
- 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
 
 
5
  sans-serif;
6
- -webkit-font-smoothing: antialiased;
7
- -moz-osx-font-smoothing: grayscale;
8
  }
9
 
10
- code {
11
- font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12
- monospace;
 
 
 
 
13
  }
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ :root {
6
+ font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
7
  sans-serif;
8
+ color: #0f172a;
9
+ background-color: #f8fafc;
10
  }
11
 
12
+ * {
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ body {
17
+ margin: 0;
18
+ min-height: 100vh;
19
  }
src/index.js CHANGED
@@ -1,13 +1,16 @@
1
  import React from 'react';
2
  import ReactDOM from 'react-dom/client';
3
  import './index.css';
4
- import App from './App';
 
5
  import reportWebVitals from './reportWebVitals';
6
 
7
  const root = ReactDOM.createRoot(document.getElementById('root'));
8
  root.render(
9
  <React.StrictMode>
10
- <App />
 
 
11
  </React.StrictMode>
12
  );
13
 
 
1
  import React from 'react';
2
  import ReactDOM from 'react-dom/client';
3
  import './index.css';
4
+ import App from './app/App.tsx';
5
+ import ErrorBoundary from './app/components/common/ErrorBoundary.tsx';
6
  import reportWebVitals from './reportWebVitals';
7
 
8
  const root = ReactDOM.createRoot(document.getElementById('root'));
9
  root.render(
10
  <React.StrictMode>
11
+ <ErrorBoundary>
12
+ <App />
13
+ </ErrorBoundary>
14
  </React.StrictMode>
15
  );
16
 
tailwind.config.js ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ module.exports = {
3
+ content: ['./src/**/*.{js,jsx,ts,tsx}'],
4
+ theme: {
5
+ extend: {},
6
+ },
7
+ plugins: [],
8
+ };
9
+