From 065e189dad7bef43c3516cdc721db6b15db5c769 Mon Sep 17 00:00:00 2001 From: brahim-guaali Date: Mon, 23 Feb 2026 00:10:29 +0400 Subject: [PATCH 1/3] Remove Talabat logo references - Remove VITE_LOGO_URL from .env.example - Remove talabat-logo.svg from .gitignore Co-Authored-By: Claude Opus 4.5 --- .env.example | 1 - .gitignore | 3 --- 2 files changed, 4 deletions(-) diff --git a/.env.example b/.env.example index 34c9c93..ae1704d 100644 --- a/.env.example +++ b/.env.example @@ -5,4 +5,3 @@ VITE_FIREBASE_STORAGE_BUCKET=your-project.firebasestorage.app VITE_FIREBASE_MESSAGING_SENDER_ID=your-sender-id VITE_FIREBASE_APP_ID=your-app-id VITE_FIREBASE_MEASUREMENT_ID=your-measurement-id -VITE_LOGO_URL=/your-logo.svg diff --git a/.gitignore b/.gitignore index e5dd6cb..1216f12 100644 --- a/.gitignore +++ b/.gitignore @@ -17,9 +17,6 @@ dist dist-ssr *.local -# Branding -public/talabat-logo.svg - # Editor directories and files .vscode/* !.vscode/extensions.json From b1f5c35a4a9f57880c21f8bb29cb52974524d9a6 Mon Sep 17 00:00:00 2001 From: brahim-guaali Date: Wed, 15 Apr 2026 07:05:52 +0400 Subject: [PATCH 2/3] Add professional repo polish: badges, LICENSE, templates, and CI - Rewrite README with badges, structured tables, and centered hero - Add MIT LICENSE file - Add CONTRIBUTING.md with development guidelines - Add GitHub issue templates (bug report, feature request) - Add pull request template with checklist - Add GitHub Actions CI workflow (lint + build on Node 20/22) - Add package.json metadata (description, keywords, repository, engines) - Add Open Graph and Twitter meta tags to index.html Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/ISSUE_TEMPLATE/bug_report.md | 27 +++++ .github/ISSUE_TEMPLATE/feature_request.md | 19 ++++ .github/PULL_REQUEST_TEMPLATE.md | 18 ++++ .github/workflows/ci.yml | 40 +++++++ CONTRIBUTING.md | 42 ++++++++ LICENSE | 21 ++++ README.md | 124 +++++++++++++--------- index.html | 8 ++ package-lock.json | 19 +--- package.json | 28 ++++- 10 files changed, 278 insertions(+), 68 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/ci.yml create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..92b9b1d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,27 @@ +--- +name: Bug Report +about: Report a bug to help us improve +title: '' +labels: bug +assignees: '' +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '...' +3. See error + +**Expected behavior** +What you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain the problem. + +**Environment** +- Browser: [e.g. Chrome 120] +- OS: [e.g. macOS 14] +- Device: [e.g. Desktop / Mobile] diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..cfdd7ed --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature Request +about: Suggest a new feature or improvement +title: '' +labels: enhancement +assignees: '' +--- + +**Problem** +What problem does this feature solve? + +**Proposed solution** +Describe the feature you'd like. + +**Alternatives considered** +Any alternative solutions or features you've considered. + +**Additional context** +Any other context, mockups, or screenshots. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..1b278c7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +## What does this PR do? + + + +## Why? + + + +## How to test + + + +## Checklist + +- [ ] `npm run lint` passes +- [ ] `npm run build` passes +- [ ] Tested on mobile viewport +- [ ] Updated README if needed diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..37d1200 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [20, 22] + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Lint + run: npm run lint + + - name: Type-check and build + run: npm run build + env: + VITE_FIREBASE_API_KEY: dummy + VITE_FIREBASE_AUTH_DOMAIN: dummy + VITE_FIREBASE_PROJECT_ID: dummy + VITE_FIREBASE_STORAGE_BUCKET: dummy + VITE_FIREBASE_MESSAGING_SENDER_ID: dummy + VITE_FIREBASE_APP_ID: dummy diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..75613ac --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,42 @@ +# Contributing to Workstream + +Thanks for your interest in contributing! Here's how to get started. + +## Development Setup + +1. Fork and clone the repo +2. Run `npm install` +3. Copy `.env.example` to `.env` and fill in your Firebase config +4. Run `npm run dev` to start the development server + +## Making Changes + +1. Create a new branch from `main` +2. Make your changes +3. Run `npm run lint` to check for lint errors +4. Run `npm run build` to verify the build passes +5. Commit your changes with a clear, descriptive message + +## Pull Requests + +- Keep PRs focused — one feature or fix per PR +- Update the README if your change affects the public API or setup +- Make sure the build passes before requesting review + +## Code Style + +- TypeScript strict mode +- Functional React components with hooks +- TailwindCSS for styling (no inline styles or CSS modules) +- Use the existing UI components in `src/components/ui/` where possible + +## Reporting Bugs + +Open an issue with: +- Steps to reproduce +- Expected vs actual behavior +- Browser and OS info + +## Feature Requests + +Open an issue describing the feature and why it would be useful. Discussion before implementation is encouraged for larger changes. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8b78d87 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Brahim Guaali + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index aabcb69..bc090a3 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,73 @@ +
+ # Workstream -A visual project tracker that shows how work branches over time. Track parallel workstreams, see when and why they diverged, and maintain context across your team. +**A visual project tracker that shows how work branches over time.** -## Features +Track parallel workstreams, see when and why they diverged, and maintain context across your team. -- **Visual Stream Tree**: Interactive canvas with drag-and-drop, zoom, and pan navigation -- **Stream Management**: Create, branch, and track workstreams in a nested hierarchy -- **Rich Context**: Add notes, change status, and link artifacts to any stream -- **Project Metrics**: Track key metrics with change percentages and optional targets -- **Stream Dependencies**: Define dependencies between streams -- **Source Types**: Categorize streams as task, investigation, meeting, blocker, or discovery -- **AI Insights**: AI-powered project analysis with TL;DR, progress overview, blockers, metrics trends, and recommendations (Gemini via Firebase AI Logic) -- **Export Formats**: Export projects as JSON (data backup), Markdown (readable document), or PDF (print) -- **Import / Export**: Full JSON import/export with metrics, streams, events, and positions preserved -- **Google Auth**: Sign in with Google via Firebase Authentication +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) +[![React](https://img.shields.io/badge/React-19-61dafb?logo=react&logoColor=white)](https://react.dev) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org) +[![Firebase](https://img.shields.io/badge/Firebase-11-ffca28?logo=firebase&logoColor=black)](https://firebase.google.com) +[![Vite](https://img.shields.io/badge/Vite-7-646cff?logo=vite&logoColor=white)](https://vite.dev) +[![TailwindCSS](https://img.shields.io/badge/Tailwind-4-06b6d4?logo=tailwindcss&logoColor=white)](https://tailwindcss.com) +[![D3.js](https://img.shields.io/badge/D3.js-7-f9a03c?logo=d3dotjs&logoColor=white)](https://d3js.org) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md) +
https://github.com/user-attachments/assets/37d18491-6b29-4698-9c46-078cf517bcaa +
+ +--- + +## Features + +- **Visual Stream Tree** — Interactive D3-powered canvas with drag-and-drop, zoom, and pan +- **Stream Branching** — Create, branch, and track workstreams in a nested hierarchy +- **Rich Context** — Add notes, change status, and link artifacts (PRs, tickets, docs) to any stream +- **Project Metrics** — Track key metrics with change percentages and optional targets +- **Stream Dependencies** — Define and visualize dependencies between streams +- **Source Types** — Categorize streams as task, investigation, meeting, blocker, or discovery +- **AI Insights** — AI-powered analysis with TL;DR, progress, blockers, metrics trends, and recommendations (Gemini 2.5 Flash via Firebase AI Logic) +- **Export** — Export projects as JSON, Markdown, or PDF +- **Import / Export** — Full JSON round-trip with metrics, streams, events, and canvas positions preserved +- **Real-time Collaboration** — Share projects with role-based access (owner, editor, viewer) +- **Google Auth** — Sign in with Google via Firebase Authentication +- **Mobile Responsive** — Fully responsive layout for desktop and mobile ## Tech Stack -- **Frontend**: React 19, TypeScript, Vite -- **Styling**: TailwindCSS 4 -- **Visualization**: D3.js -- **AI**: Firebase AI Logic (Gemini 2.5 Flash) -- **Backend**: Firebase (Firestore + Auth) -- **Hosting**: Firebase Hosting +| Layer | Technology | +|-------|-----------| +| **Frontend** | React 19, TypeScript 5.9, Vite 7 | +| **Styling** | TailwindCSS 4 | +| **Visualization** | D3.js 7 | +| **AI** | Firebase AI Logic (Gemini 2.5 Flash) | +| **Backend** | Firebase (Firestore + Auth) | +| **Hosting** | Firebase Hosting | ## Getting Started ### Prerequisites -- Node.js 20+ +- [Node.js](https://nodejs.org) 20+ - A Firebase project with Firestore and Authentication enabled ### Installation ```bash +# Clone the repository +git clone https://github.com/brahim-guaali/Workstream.git +cd Workstream + # Install dependencies npm install -# Create .env with your Firebase config -cat > .env << 'EOF' -VITE_FIREBASE_API_KEY=your-api-key -VITE_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com -VITE_FIREBASE_PROJECT_ID=your-project-id -VITE_FIREBASE_STORAGE_BUCKET=your-project.firebasestorage.app -VITE_FIREBASE_MESSAGING_SENDER_ID=your-sender-id -VITE_FIREBASE_APP_ID=your-app-id -VITE_FIREBASE_MEASUREMENT_ID=your-measurement-id -VITE_LOGO_URL=/your-logo.svg -EOF +# Copy the example env file and fill in your Firebase config +cp .env.example .env # Start development server npm run dev @@ -60,7 +76,7 @@ npm run dev ### Environment Variables | Variable | Required | Description | -|----------|----------|-------------| +|----------|:--------:|-------------| | `VITE_FIREBASE_API_KEY` | Yes | Firebase API key | | `VITE_FIREBASE_AUTH_DOMAIN` | Yes | Firebase auth domain | | `VITE_FIREBASE_PROJECT_ID` | Yes | Firebase project ID | @@ -83,27 +99,27 @@ npm run dev ``` src/ ├── components/ -│ ├── auth/ # SignIn -│ ├── layout/ # Header, Layout -│ ├── project/ # ProjectList, ProjectCard -│ ├── stream/ # StreamDetail, AddStreamModal -│ ├── visualization/ # StreamTree (D3 canvas) -│ └── ui/ # Button, Modal, Input, Textarea -├── contexts/ # AuthContext -├── hooks/ # useProjects, useStreams, useEvents, useProjectInsights -├── lib/ # firebase.ts, utils.ts, exportDocument.ts -├── types/ # database.ts +│ ├── auth/ # Sign-in flow +│ ├── layout/ # Header, Layout shell +│ ├── project/ # Project list, cards, sharing +│ ├── stream/ # Stream detail panel, modals +│ ├── visualization/ # D3 stream tree canvas +│ └── ui/ # Reusable primitives (Button, Modal, Input, etc.) +├── contexts/ # Auth context provider +├── hooks/ # Custom hooks (projects, streams, events, AI insights) +├── lib/ # Firebase init, utilities, export logic +├── types/ # TypeScript type definitions └── pages/ # HomePage, ProjectPage ``` -## Available Scripts +## Scripts -```bash -npm run dev # Start development server -npm run build # Type-check and build for production -npm run preview # Preview production build -npm run lint # Run ESLint -``` +| Command | Description | +|---------|-------------| +| `npm run dev` | Start development server | +| `npm run build` | Type-check and build for production | +| `npm run preview` | Preview production build locally | +| `npm run lint` | Run ESLint | ## Deployment @@ -112,6 +128,16 @@ npm run build firebase deploy --only hosting --project your-project-id ``` +## Contributing + +Contributions are welcome! Please read the [Contributing Guide](CONTRIBUTING.md) before submitting a pull request. + ## License -MIT +This project is licensed under the [MIT License](LICENSE). + +--- + +
+ Built with React, D3.js, Firebase, and a lot of coffee. +
diff --git a/index.html b/index.html index 98c4883..5f5ba6c 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,14 @@ + + + + + + + + Workstream diff --git a/package-lock.json b/package-lock.json index eb061dc..ab02dc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -982,7 +981,6 @@ "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.13.2.tgz", "integrity": "sha512-jwtMmJa1BXXDCiDx1vC6SFN/+HfYG53UkfJa6qeN5ogvOunzbFDO3wISZy5n9xgYFUrEP6M7e8EG++riHNTv9w==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@firebase/component": "0.6.18", "@firebase/logger": "0.4.4", @@ -1049,7 +1047,6 @@ "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.4.2.tgz", "integrity": "sha512-LssbyKHlwLeiV8GBATyOyjmHcMpX/tFjzRUCS1jnwGAew1VsBB4fJowyS5Ud5LdFbYpJeS+IQoC+RQxpK7eH3Q==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@firebase/app": "0.13.2", "@firebase/component": "0.6.18", @@ -1065,8 +1062,7 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/@firebase/auth": { "version": "1.10.8", @@ -1517,7 +1513,6 @@ "integrity": "sha512-zGlBn/9Dnya5ta9bX/fgEoNC3Cp8s6h+uYPYaDieZsFOAdHP/ExzQ/eaDgxD3GOROdPkLKpvKY0iIzr9adle0w==", "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.1.0" }, @@ -2768,7 +2763,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2834,7 +2828,6 @@ "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.56.0", "@typescript-eslint/types": "8.56.0", @@ -3105,7 +3098,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3232,7 +3224,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -3771,7 +3762,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -4031,7 +4021,6 @@ "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -6143,7 +6132,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -6239,7 +6227,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -6249,7 +6236,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -6745,7 +6731,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6946,7 +6931,6 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -7150,7 +7134,6 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 4782376..62d25c9 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,34 @@ { "name": "workstream", "private": true, - "version": "0.0.0", + "version": "1.0.0", + "description": "A visual project tracker that shows how work branches over time", + "author": "Brahim Guaali", + "license": "MIT", + "homepage": "https://github.com/brahim-guaali/Workstream#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/brahim-guaali/Workstream.git" + }, + "bugs": { + "url": "https://github.com/brahim-guaali/Workstream/issues" + }, + "keywords": [ + "project-tracker", + "workstream", + "visualization", + "d3", + "react", + "firebase", + "project-management", + "stream-tree", + "ai-insights", + "collaboration" + ], "type": "module", + "engines": { + "node": ">=20" + }, "scripts": { "dev": "vite", "build": "tsc -b && vite build", From ca1627ab144e76e5e8938604a33a5ff25fd2e333 Mon Sep 17 00:00:00 2001 From: brahim-guaali Date: Wed, 15 Apr 2026 07:08:47 +0400 Subject: [PATCH 3/3] Fix lint errors: remove synchronous setState in useEffect guards Co-Authored-By: Claude Opus 4.6 (1M context) --- src/hooks/useProjects.ts | 3 +-- src/hooks/useRegisteredUsers.ts | 2 -- src/hooks/useSharedProjects.ts | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/hooks/useProjects.ts b/src/hooks/useProjects.ts index 8ee1305..85a3398 100644 --- a/src/hooks/useProjects.ts +++ b/src/hooks/useProjects.ts @@ -35,11 +35,10 @@ export function useProject(projectId: string | undefined, ownerId?: string) { useEffect(() => { if (!user || !projectId || !resolvedOwnerId) { - setProject(null); - setLoading(false); return; } + // eslint-disable-next-line react-hooks/set-state-in-effect -- intentional: set loading before subscribing setLoading(true); const projectRef = doc(db, 'users', resolvedOwnerId, 'projects', projectId); const unsubscribe = onSnapshot(projectRef, (snap) => { diff --git a/src/hooks/useRegisteredUsers.ts b/src/hooks/useRegisteredUsers.ts index 6d20744..85f45d6 100644 --- a/src/hooks/useRegisteredUsers.ts +++ b/src/hooks/useRegisteredUsers.ts @@ -16,8 +16,6 @@ export function useRegisteredUsers(excludeEmails: string[]) { useEffect(() => { if (!user) { - setUsers([]); - setLoading(false); return; } diff --git a/src/hooks/useSharedProjects.ts b/src/hooks/useSharedProjects.ts index 9b932b5..5008bf0 100644 --- a/src/hooks/useSharedProjects.ts +++ b/src/hooks/useSharedProjects.ts @@ -17,11 +17,10 @@ export function useSharedProjects() { useEffect(() => { if (!user) { - setSharedProjects([]); - setLoading(false); return; } + // eslint-disable-next-line react-hooks/set-state-in-effect -- intentional: set loading before subscribing setLoading(true); const q = query( collection(db, 'shared_projects'),