Skip to content

Conversation

@cj-vana
Copy link
Collaborator

@cj-vana cj-vana commented Nov 30, 2025

User description

  • Add DeprecationNoticeModal component with eventools branding

    • Gentle/positive messaging about platform transition
    • Links to eventools.io for beta signup
    • Mentions upcoming data export and self-hosting docs
    • Shows once per user via localStorage persistence
  • Integrate modal into Landing and Dashboard pages

    • Shared localStorage key so dismissing on one page dismisses both
  • Fix StagePlotEditor TDZ (Temporal Dead Zone) bug

    • Reorder code so collaborationEnabled and broadcast are defined before being referenced in useEffect dependency array
    • Fixes blank page error in production builds

🤖 Generated with Claude Code


PR Type

Enhancement, Bug fix


Description

  • Add DeprecationNoticeModal component with eventools branding

    • Gentle messaging about platform transition to eventools
    • Links to beta signup and mentions data export/self-hosting docs
    • Persists dismissal state via localStorage across pages
  • Integrate modal into Landing and Dashboard pages

    • Shared localStorage key ensures consistent dismissal behavior
  • Fix StagePlotEditor Temporal Dead Zone bug

    • Reorder useEffect hooks to define collaborationEnabled and broadcast before dependency array usage
    • Resolves blank page error in production builds

Diagram Walkthrough

flowchart LR
  A["New DeprecationNoticeModal<br/>Component"] --> B["Landing Page<br/>Integration"]
  A --> C["Dashboard Page<br/>Integration"]
  B --> D["Shared localStorage<br/>Persistence"]
  C --> D
  E["StagePlotEditor<br/>useEffect Reordering"] --> F["Fix TDZ Bug<br/>& Blank Page"]
Loading

File Walkthrough

Relevant files
Enhancement
DeprecationNoticeModal.tsx
Create DeprecationNoticeModal component                                   

apps/web/src/components/DeprecationNoticeModal.tsx

  • New React component displaying deprecation notice with eventools
    branding
  • Features modal overlay with close button and external link to beta
    signup
  • Includes messaging about data export and self-hosting documentation
  • Styled with dark theme, backdrop blur, and indigo accent colors
+84/-0   
Dashboard.tsx
Integrate deprecation modal into Dashboard                             

apps/web/src/pages/Dashboard.tsx

  • Import DeprecationNoticeModal component
  • Add localStorage-based state management for modal visibility
  • Initialize showDeprecationModal state from localStorage on component
    mount
  • Add handleDismissDeprecation handler to persist dismissal and close
    modal
  • Render modal at bottom of component with shared localStorage key
+12/-0   
Landing.tsx
Integrate deprecation modal into Landing page                       

apps/web/src/pages/Landing.tsx

  • Import DeprecationNoticeModal component and add useState hook
  • Add localStorage-based state management for modal visibility
  • Initialize showDeprecationModal state from localStorage on component
    mount
  • Add handleDismissDeprecation handler to persist dismissal and close
    modal
  • Render modal at bottom of component with shared localStorage key
+14/-1   
Bug fix
StagePlotEditor.tsx
Fix StagePlotEditor TDZ bug via hook reordering                   

apps/web/src/pages/StagePlotEditor.tsx

  • Move two useEffect hooks (name initialization and debounced sync)
    after usePresence hook definition
  • Reorder code to ensure collaborationEnabled and broadcast variables
    are defined before being referenced in useEffect dependency arrays
  • Fixes Temporal Dead Zone bug that caused blank page errors in
    production builds
  • No functional changes to the hooks themselves, only repositioning
+37/-37 

@netlify
Copy link

netlify bot commented Nov 30, 2025

Deploy Preview for sounddocsbeta ready!

Name Link
🔨 Latest commit 91381bc
🔍 Latest deploy log https://app.netlify.com/projects/sounddocsbeta/deploys/692c5a0dc836c30008395e99
😎 Deploy Preview https://deploy-preview-119--sounddocsbeta.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Nov 30, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Untrusted asset load

Description: The modal loads an external image via a relative path (/eventools-logo.png) without
integrity checks or error handling, which can aid clickjacking/phishing if the asset path
is controlled or replaced on the CDN; consider embedding, hashing, or restricting the
asset source.
DeprecationNoticeModal.tsx [31-33]

Referred Code
<div className="flex flex-col items-center text-center">
  <img src="/eventools-logo.png" alt="eventools" className="h-16 w-16 mb-6" />
External link safety

Description: External link uses target="_blank" and rel="noopener noreferrer", which is good, but the
href is hardcoded to an external domain; ensure allowlist validation if this ever becomes
user-configurable to prevent open redirect/phishing risks.
DeprecationNoticeModal.tsx [61-69]

Referred Code
<a
  href="https://eventools.io"
  target="_blank"
  rel="noopener noreferrer"
  className="flex-1 inline-flex items-center justify-center px-6 py-3 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold rounded-lg transition-colors"
>
  Sign Up for eventools Beta
  <ExternalLink className="h-4 w-4 ml-2" />
</a>
localStorage SSR access

Description: Accessing localStorage during initial state derivation can throw in server-side rendering
or restricted environments, potentially exposing user data flow and causing crashes; wrap
in try/catch or gate on typeof window !== 'undefined'.
Dashboard.tsx [29-31]

Referred Code
const [showDeprecationModal, setShowDeprecationModal] = useState(() => {
  return localStorage.getItem(DEPRECATION_NOTICE_KEY) !== "true";
});
localStorage hard dependency

Description: Writing to localStorage without guarding for storage availability or quota errors can
reveal usage patterns and cause unhandled exceptions in private mode; add try/catch and
feature detection.
Dashboard.tsx [75-78]

Referred Code
const handleDismissDeprecation = () => {
  localStorage.setItem(DEPRECATION_NOTICE_KEY, "true");
  setShowDeprecationModal(false);
};
localStorage SSR access

Description: Initializing state by reading localStorage at module render time can break in SSR and leak
assumptions about browser environment; guard with window checks or defer to useEffect with
safe defaults.
Landing.tsx [14-16]

Referred Code
const [showDeprecationModal, setShowDeprecationModal] = useState(() => {
  return localStorage.getItem(DEPRECATION_NOTICE_KEY) !== "true";
});
localStorage hard dependency

Description: Persisting dismissal to localStorage without error handling may throw in restricted
contexts and lacks expiration/rotation, leading to sticky UX and potential privacy
concerns; add try/catch and consider a time-bounded flag.
Landing.tsx [18-21]

Referred Code
const handleDismissDeprecation = () => {
  localStorage.setItem(DEPRECATION_NOTICE_KEY, "true");
  setShowDeprecationModal(false);
};
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit logs: The new user-facing deprecation modal dismissal persists to localStorage without any
accompanying audit logging of the user action, which may be acceptable for non-critical UX
actions but cannot be confirmed from the diff.

Referred Code
const handleDismissDeprecation = () => {
  localStorage.setItem(DEPRECATION_NOTICE_KEY, "true");
  setShowDeprecationModal(false);
};

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Storage edge cases: Access to localStorage for modal state lacks try/catch and fallback handling, which could
fail in SSR or restricted environments leading to runtime errors or incorrect state.

Referred Code
const [showDeprecationModal, setShowDeprecationModal] = useState(() => {
  return localStorage.getItem(DEPRECATION_NOTICE_KEY) !== "true";
});

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
External link target: The modal adds an external link using target="_blank" which is mitigated by
rel="noopener noreferrer" but no additional input validation is evident for any
user-controlled data in this component; overall security implications cannot be fully
assessed from the diff.

Referred Code
<a
  href="https://eventools.io"
  target="_blank"
  rel="noopener noreferrer"
  className="flex-1 inline-flex items-center justify-center px-6 py-3 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold rounded-lg transition-colors"
>
  Sign Up for eventools Beta
  <ExternalLink className="h-4 w-4 ml-2" />
</a>

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Nov 30, 2025

CI Feedback 🧐

(Feedback updated until commit d6d8db0)

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: pr-checks-summary

Failed stage: Summary [❌]

Failure summary:

The workflow failed because the summary step detected failed TypeScript checks and explicitly exited
with a non-zero status:
- It printed "❌ TypeScript checks: FAILED" since the TypeScript check result
variable was failure.
- In the "Overall status" block, the condition [ "failure" == "failure" ]
evaluated to true, triggering:
- Output: "❌ Overall Status: FAILED"
- Command: exit 1
- This
caused the job to end with "Process completed with exit code 1."

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

22:  Secret source: Actions
23:  Prepare workflow directory
24:  Prepare all required actions
25:  Complete job name: pr-checks-summary
26:  ##[group]Run echo "## PR Checks Summary"
27:  �[36;1mecho "## PR Checks Summary"�[0m
28:  �[36;1mecho ""�[0m
29:  �[36;1m�[0m
30:  �[36;1m# Check TypeScript�[0m
31:  �[36;1mif [ "true" == "true" ]; then�[0m
32:  �[36;1m  if [ "failure" == "success" ]; then�[0m
33:  �[36;1m    echo "✅ TypeScript checks: PASSED"�[0m
34:  �[36;1m  elif [ "failure" == "skipped" ]; then�[0m
35:  �[36;1m    echo "⏭️  TypeScript checks: SKIPPED (no changes)"�[0m
36:  �[36;1m  else�[0m
37:  �[36;1m    echo "❌ TypeScript checks: FAILED"�[0m
38:  �[36;1m  fi�[0m
39:  �[36;1melse�[0m
40:  �[36;1m  echo "⏭️  TypeScript checks: No files changed"�[0m
41:  �[36;1mfi�[0m
42:  �[36;1m�[0m
43:  �[36;1m# Check Python�[0m
44:  �[36;1mif [ "false" == "true" ]; then�[0m
45:  �[36;1m  if [ "skipped" == "success" ]; then�[0m
46:  �[36;1m    echo "✅ Python checks: PASSED"�[0m
47:  �[36;1m  elif [ "skipped" == "skipped" ]; then�[0m
48:  �[36;1m    echo "⏭️  Python checks: SKIPPED (no changes)"�[0m
49:  �[36;1m  else�[0m
50:  �[36;1m    echo "❌ Python checks: FAILED"�[0m
51:  �[36;1m  fi�[0m
52:  �[36;1melse�[0m
53:  �[36;1m  echo "⏭️  Python checks: No files changed"�[0m
54:  �[36;1mfi�[0m
55:  �[36;1m�[0m
56:  �[36;1m# Check SQL�[0m
57:  �[36;1mif [ "false" == "true" ]; then�[0m
58:  �[36;1m  if [ "skipped" == "success" ]; then�[0m
59:  �[36;1m    echo "✅ SQL checks: PASSED"�[0m
60:  �[36;1m  elif [ "skipped" == "skipped" ]; then�[0m
61:  �[36;1m    echo "⏭️  SQL checks: SKIPPED (no changes)"�[0m
62:  �[36;1m  else�[0m
63:  �[36;1m    echo "❌ SQL checks: FAILED"�[0m
64:  �[36;1m  fi�[0m
65:  �[36;1melse�[0m
66:  �[36;1m  echo "⏭️  SQL checks: No files changed"�[0m
67:  �[36;1mfi�[0m
68:  �[36;1m�[0m
69:  �[36;1m# Overall status�[0m
70:  �[36;1mecho ""�[0m
71:  �[36;1mif [ "failure" == "failure" ] || \�[0m
72:  �[36;1m   [ "skipped" == "failure" ] || \�[0m
73:  �[36;1m   [ "skipped" == "failure" ]; then�[0m
74:  �[36;1m  echo "❌ **Overall Status: FAILED**"�[0m
75:  �[36;1m  echo "Please fix the issues above before merging."�[0m
76:  �[36;1m  exit 1�[0m
77:  �[36;1melse�[0m
78:  �[36;1m  echo "✅ **Overall Status: PASSED**"�[0m
79:  �[36;1m  echo "All checks on changed files have passed!"�[0m
80:  �[36;1mfi�[0m
81:  shell: /usr/bin/bash -e {0}
82:  ##[endgroup]
83:  ## PR Checks Summary
84:  ❌ TypeScript checks: FAILED
85:  ⏭️  Python checks: No files changed
86:  ⏭️  SQL checks: No files changed
87:  ❌ **Overall Status: FAILED**
88:  Please fix the issues above before merging.
89:  ##[error]Process completed with exit code 1.
90:  Cleaning up orphan processes

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Nov 30, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Avoid SSR errors with client-side logic

Move localStorage access from the useState initializer into a useEffect hook to
prevent server-side rendering errors, ensuring the code runs only on the client.

apps/web/src/pages/Landing.tsx [11-21]

 const DEPRECATION_NOTICE_KEY = "sounddocs-deprecation-notice-dismissed";
 
 const Landing: React.FC = () => {
-  const [showDeprecationModal, setShowDeprecationModal] = useState(() => {
-    return localStorage.getItem(DEPRECATION_NOTICE_KEY) !== "true";
-  });
+  const [showDeprecationModal, setShowDeprecationModal] = useState(false);
+
+  useEffect(() => {
+    const dismissed = localStorage.getItem(DEPRECATION_NOTICE_KEY) === "true";
+    if (!dismissed) {
+      setShowDeprecationModal(true);
+    }
+  }, []);
 
   const handleDismissDeprecation = () => {
     localStorage.setItem(DEPRECATION_NOTICE_KEY, "true");
     setShowDeprecationModal(false);
   };
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies that accessing localStorage in a useState initializer will cause a crash during server-side rendering and proposes the standard, correct fix.

High
High-level
Centralize modal logic into a hook

Extract the duplicated state management logic for the deprecation modal from the
Landing and Dashboard pages into a single, reusable custom React hook
(useDeprecationNotice) to improve maintainability.

Examples:

apps/web/src/pages/Dashboard.tsx [22-78]
const DEPRECATION_NOTICE_KEY = "sounddocs-deprecation-notice-dismissed";

const Dashboard = () => {
  const navigate = useNavigate();
  const { user: authUser, loading: authLoading } = useAuth();

  const [loading, setLoading] = useState(true);
  const [showDeprecationModal, setShowDeprecationModal] = useState(() => {
    return localStorage.getItem(DEPRECATION_NOTICE_KEY) !== "true";
  });

 ... (clipped 47 lines)
apps/web/src/pages/Landing.tsx [11-21]
const DEPRECATION_NOTICE_KEY = "sounddocs-deprecation-notice-dismissed";

const Landing: React.FC = () => {
  const [showDeprecationModal, setShowDeprecationModal] = useState(() => {
    return localStorage.getItem(DEPRECATION_NOTICE_KEY) !== "true";
  });

  const handleDismissDeprecation = () => {
    localStorage.setItem(DEPRECATION_NOTICE_KEY, "true");
    setShowDeprecationModal(false);

 ... (clipped 1 lines)

Solution Walkthrough:

Before:

// In both Landing.tsx and Dashboard.tsx
const DEPRECATION_NOTICE_KEY = "sounddocs-deprecation-notice-dismissed";

const Component = () => {
  const [showDeprecationModal, setShowDeprecationModal] = useState(() => {
    return localStorage.getItem(DEPRECATION_NOTICE_KEY) !== "true";
  });

  const handleDismissDeprecation = () => {
    localStorage.setItem(DEPRECATION_NOTICE_KEY, "true");
    setShowDeprecationModal(false);
  };

  return (
    <DeprecationNoticeModal isOpen={showDeprecationModal} onClose={handleDismissDeprecation} />
  );
}

After:

// In a new file, e.g., hooks/useDeprecationNotice.ts
const DEPRECATION_NOTICE_KEY = "sounddocs-deprecation-notice-dismissed";
export const useDeprecationNotice = () => {
  const [isOpen, setIsOpen] = useState(() => localStorage.getItem(DEPRECATION_NOTICE_KEY) !== "true");

  const onClose = () => {
    localStorage.setItem(DEPRECATION_NOTICE_KEY, "true");
    setIsOpen(false);
  };
  return { isOpen, onClose };
}

// In both Landing.tsx and Dashboard.tsx
const Component = () => {
  const { isOpen, onClose } = useDeprecationNotice();
  return <DeprecationNoticeModal isOpen={isOpen} onClose={onClose} />;
}
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies duplicated state logic in Dashboard.tsx and Landing.tsx and proposes a custom hook, which is a best practice that significantly improves maintainability and code quality.

Medium
  • Update

- Add DeprecationNoticeModal component with eventools branding
  - Gentle/positive messaging about platform transition
  - Links to eventools.io for beta signup
  - Mentions upcoming data export and self-hosting docs

- Create useDeprecationNotice hook for SSR-safe localStorage access
  - Centralizes modal logic for Landing and Dashboard pages
  - Uses useEffect to avoid SSR hydration errors

- Integrate modal into Landing and Dashboard pages
  - Shared localStorage key so dismissing on one page dismisses both

- Fix StagePlotEditor TDZ (Temporal Dead Zone) bug
  - Reorder code so collaborationEnabled and broadcast are defined
    before being referenced in useEffect dependency array
  - Fixes blank page error in production builds

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@cj-vana cj-vana merged commit 6d4f33f into beta Nov 30, 2025
6 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant