Skip to content

fix(dashboard): bypass Rive in folder create/subfolder dialogs#1888

Open
alexis-morain wants to merge 1 commit into
CapSoftware:mainfrom
alexis-morain:fix/rive-folder-dialog-crash
Open

fix(dashboard): bypass Rive in folder create/subfolder dialogs#1888
alexis-morain wants to merge 1 commit into
CapSoftware:mainfrom
alexis-morain:fix/rive-folder-dialog-crash

Conversation

@alexis-morain
Copy link
Copy Markdown
Contributor

@alexis-morain alexis-morain commented Jun 6, 2026

Summary

NewFolderDialog and SubfolderDialog render four sibling Rive components (NormalFolder / BlueFolder / RedFolder / YellowFolder), each calling useRive with the same riveFile returned by a parent useRiveFile. On Next 16 + React 19 + @rive-app/react-canvas@^4.18.7 this triggers a race between the four useRive inits when the dialog mounts — the runtime ends up reading isPlaying / stateMachines on an undefined Rive instance, throws inside setupRiveListeners, and the React reconciler bounces between two chunks in an infinite up/ud recursion that takes down the whole page.

Repro

  1. Self-host or run main with React 19 / Next 16.
  2. Dashboard → caps → click New Folder.
  3. Page crashes; console shows:
    Uncaught TypeError: Cannot read properties of undefined (reading 'isPlaying')
    TypeError: Cannot read properties of undefined (reading 'stateMachines')
        at t.setupRiveListeners
    
    followed by an infinite iv → up → ud → up → ud … stack.

Fix

Replace the four sibling Rive components in the two creation dialogs with a single FontAwesomeIcon (faFolder) tinted per colour choice. The dialog still shows four labelled, selectable swatches; only the hover open/close animation is dropped.

Folder cards on the dashboard (Folder.tsx) keep their Rive runtime because each card owns its own useRive call and never shares a riveFile — that path doesn't hit the race.

Test plan

  • Open New Folder → dialog renders, four colour swatches visible.
  • Pick a colour → swatch highlights, Create button enables when a name is typed.
  • Folder created, dashboard refreshes.
  • Same flow from inside a folder via New Subfolder.
  • Existing folder cards on the dashboard still animate on hover (Rive unaffected).

Notes

This is a workaround targeting the race, not an upstream Rive fix. A proper fix probably belongs in @rive-app/react-canvas (init sequencing when a shared riveFile is consumed by multiple useRive hooks). Happy to revert if a newer rive-react release resolves it.

Greptile Summary

Fixes a page-crashing race condition in the folder creation dialogs caused by four sibling useRive calls sharing a single riveFile instance on React 19 / Next 16. The Rive components and their shared file loader are removed from both NewFolderDialog and SubfolderDialog, replaced with static FontAwesomeIcon swatches tinted per colour choice.

  • Removes useRiveFile, all four *Folder Rive components, and the folderRefs imperative animation handles from both dialogs; hover open/close animations are intentionally dropped as a known trade-off.
  • Replaces the animated swatches with a FontAwesomeIcon faFolder coloured via inline style, preserving the four selectable colour options and the existing selection/disabled-state logic unchanged.
  • Dashboard Folder.tsx cards are unaffected as each owns its own useRive call and does not share a riveFile.

Confidence Score: 4/5

Safe to merge — removes the crash path with a minimal, well-scoped change; the only findings are cosmetic redundancies in the icon colour props.

The change is a targeted removal of Rive from two dialog components, fixing a hard crash. Core folder-creation logic (RPC call, form state, error handling) is untouched. The redundant color / style.color dual-specification in both files is cosmetic and carries no functional risk.

No files require special attention beyond the minor icon-prop redundancy already flagged.

Important Files Changed

Filename Overview
apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx Removes Rive runtime and shared riveFile from the New Folder dialog, replacing four animated folder components with static FontAwesomeIcon swatches tinted per colour option. Minor: both the color prop and style.color are set on the icon, and size is expressed as inline style strings instead of Tailwind utilities.
apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx Mirrors the NewFolderDialog change: Rive components removed, FontAwesomeIcon substituted. Same minor redundancy with dual colour specification and inline-style sizing.

Comments Outside Diff (2)

  1. apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx, line 105-117 (link)

    P2 The color prop on FontAwesomeIcon and style={{ color: option.color }} both set the same CSS colour — the color prop maps to the SVG color attribute (inherited as currentColor), while the inline style does the same via CSS. Either one alone is sufficient; the duplicate is redundant. Same pattern appears in SubfolderDialog.tsx.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx
    Line: 105-117
    
    Comment:
    The `color` prop on `FontAwesomeIcon` and `style={{ color: option.color }}` both set the same CSS colour — the `color` prop maps to the SVG `color` attribute (inherited as `currentColor`), while the inline style does the same via CSS. Either one alone is sufficient; the duplicate is redundant. Same pattern appears in `SubfolderDialog.tsx`.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  2. apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx, line 110-122 (link)

    P2 Same redundant dual colour-specification as in NewFolderDialog: the color prop and style={{ color: option.color }} both control the icon colour; drop one.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx
    Line: 110-122
    
    Comment:
    Same redundant dual colour-specification as in `NewFolderDialog`: the `color` prop and `style={{ color: option.color }}` both control the icon colour; drop one.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx:105-117
The `color` prop on `FontAwesomeIcon` and `style={{ color: option.color }}` both set the same CSS colour — the `color` prop maps to the SVG `color` attribute (inherited as `currentColor`), while the inline style does the same via CSS. Either one alone is sufficient; the duplicate is redundant. Same pattern appears in `SubfolderDialog.tsx`.

```suggestion
								>
									<FontAwesomeIcon
										icon={faFolder}
										style={{ color: option.color, width: "40px", height: "40px" }}
									/>
									<p className="text-xs text-gray-10">{option.label}</p>
								</div>
							);
						})}
					</div>
				</div>
				<DialogFooter>
```

### Issue 2 of 2
apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx:110-122
Same redundant dual colour-specification as in `NewFolderDialog`: the `color` prop and `style={{ color: option.color }}` both control the icon colour; drop one.

```suggestion
								>
									<FontAwesomeIcon
										icon={faFolder}
										style={{ color: option.color, width: "40px", height: "40px" }}
									/>
									<p className="text-xs text-gray-10">{option.label}</p>
								</div>
							);
						})}
					</div>
				</div>
				<DialogFooter>
```

Reviews (1): Last reviewed commit: "fix(dashboard): bypass Rive in folder cr..." | Re-trigger Greptile

The NewFolderDialog and SubfolderDialog render four sibling components
(NormalFolder / BlueFolder / RedFolder / YellowFolder) that each call
useRive with the same riveFile retrieved from a parent useRiveFile call.

Under React 19 / Next 16, this triggers a race between the four useRive
inits when the dialog mounts: the runtime ends up reading isPlaying /
stateMachines on an undefined Rive instance, throws an Uncaught
TypeError inside setupRiveListeners, and bounces between two internal
chunks in an infinite up/ud recursion that takes down the page.

Replace the four Rive components with a single FontAwesome faFolder
icon tinted per color choice. The visual remains four labelled,
selectable swatches; only the hover open/close animation is dropped.
The folder cards on the dashboard (Folder.tsx) keep their Rive runtime
because each card owns its own useRive call and never shares a
riveFile, so they don't hit the race.

Repro: dashboard / caps -> click "New Folder" on Next 16 + React 19 +
@rive-app/react-canvas@^4.18.7 -> dialog crashes, page becomes blank.

After the patch the dialog opens reliably and folder creation works
unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant