feat: implement UI component library and scaffold application structu…#1
Conversation
…re for workflow management
|
React Doctor found 40 new issues in 8 files · 40 warnings · score 54 / 100 (Critical) · 11 fixed · vs 40 warnings
Reviewed by React Doctor for commit |
| return `${days}d ago`; | ||
| } | ||
|
|
||
| export default function FlowPage() { |
There was a problem hiding this comment.
React Doctor · react-doctor/no-giant-component (warning)
Component "FlowPage" is 354 lines long, which is hard to read & change. Split it into a few smaller components.
Fix → Pull each section into its own component so the parent is easier to read, test, and change.
| return `${days}d ago`; | ||
| } | ||
|
|
||
| export default function FlowPage() { |
There was a problem hiding this comment.
React Doctor · react-doctor/prefer-useReducer (warning)
6 useState calls in "FlowPage" can each trigger a separate render.
Fix → Group related state in useReducer so one logical update does not fan out into separate renders.
|
|
||
| useEffect(() => { | ||
| if (isLoaded && !isSignedIn) { | ||
| router.push("/"); |
There was a problem hiding this comment.
React Doctor · react-doctor/nextjs-no-client-side-redirect (warning)
router.push() in useEffect flashes the wrong page before redirecting.
Fix → Avoid redirects inside useEffect. Use an event handler, middleware, or server-side redirect (App Router: redirect() from next/navigation; Pages Router: getServerSideProps redirect)
| router.push("/"); | ||
| return; | ||
| } | ||
| if (isLoaded) fetchWorkflows(); |
There was a problem hiding this comment.
React Doctor · react-doctor/no-derived-state (warning)
"workflows" is only set here from other values, so storing it costs an extra render.
Fix → Work out the value while rendering (or with useMemo if it's expensive) instead of copying it into useState through a useEffect. See https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state
| className="group text-left bg-white border border-gray-200 rounded-xl overflow-hidden hover:shadow-md transition-all cursor-pointer flex flex-col w-full" | ||
| > | ||
| <div className="aspect-[4/3] relative overflow-hidden bg-gray-100 w-full"> | ||
| <Image |
There was a problem hiding this comment.
React Doctor · react-doctor/nextjs-image-missing-sizes (warning)
next/image uses fill without sizes, so your users download the largest image.
Fix → Add sizes matching your layout so next/image does not assume the largest candidate and make users download oversized images.
| <Tooltip> | ||
| <TooltipTrigger | ||
| render={ | ||
| <button |
There was a problem hiding this comment.
React Doctor · react-doctor/control-has-associated-label (warning)
Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Fix → Give every interactive control a label screen readers can read.
| <Gift className="size-5" /> | ||
| Claim Offer | ||
| </Button> | ||
| <ChevronDown className="size-4 text-gray-400 -mt-0.5 animate-bounce-subtle" /> |
There was a problem hiding this comment.
React Doctor · react-doctor/no-inline-bounce-easing (warning)
Your users see a dated, tacky animate-bounce, so use a subtle ease-out transform for a smoother finish.
Fix → Use cubic-bezier(0.16, 1, 0.3, 1) (ease-out-expo) for a natural finish. Real objects don't bounce.
| return () => clearInterval(interval); | ||
| }, []); | ||
|
|
||
| const pad = (n: number) => String(n).padStart(2, "0"); |
There was a problem hiding this comment.
React Doctor · react-doctor/prefer-module-scope-pure-function (warning)
pad inside PromoBanner uses no local state but is rebuilt on every render, so it wastes work & breaks memoized children. Move it to the top of the file, outside the component.
Fix → Move the function above the component, at the top of the file. It doesn't use local state, so rebuilding it each update is wasted work.
| const SidebarContext = React.createContext<SidebarContextProps | null>(null); | ||
|
|
||
| function useSidebar() { | ||
| const context = React.useContext(SidebarContext); |
There was a problem hiding this comment.
React Doctor · react-doctor/no-react19-deprecated-apis (warning)
useContext is replaced by use() in React 19, which reads context inside ifs & loops too, so switch to import { use } from 'react'.
Fix → Pass ref as a normal prop on function components, since forwardRef isn't needed in React 19. Replace useContext(X) with use(X). Only runs on React 19+ projects.
| const { toggleSidebar } = useSidebar(); | ||
|
|
||
| return ( | ||
| <button |
There was a problem hiding this comment.
React Doctor · react-doctor/button-has-type (warning)
Your users can submit the form by accident because a <button> with no type defaults to submit.
Fix → Set an explicit button type so plain buttons do not submit forms by accident: type="button", "submit", or "reset".
…re for workflow management