--- name: react-to-nextjs-components description: > Implements Phase B of the React-to-Next.js migration plan: classifies and migrates React components to Server Components (RSC) or Client Components (RCC), extracts Context providers into client wrappers, and adds 'use client' directives where required. Use this skill whenever the user asks to migrate components, convert JSX to RSC, add use client directives, or execute Phase B of a MIGRATION_PLAN.md. Requires Phase A (routing) to be complete first. metadata: author: app-dev-exp version: "1.0" --- # react-to-nextjs-components Implements **Phase B** of the migration plan: component classification and migration to RSC/RCC. Writes files directly into `ms-conference-webapp/`. --- ## Preconditions ```bash # Always read paths first cat agents/shared/context/monorepo-paths.md WEBAPP_ROOT="conference-manager/ms-conference-webapp" WEBAPP_LEGACY="conference-manager/ms-conference-webapp/legacy" WEBAPP_APP="conference-manager/ms-conference-webapp/src/app" FRONTEND_PLANS="conference-manager/ms-conference-webapp/plans" # Phase A must be complete grep "Phase A" $FRONTEND_PLANS/MIGRATION_PLAN.md | grep "✅" # No TypeScript errors from Phase A cd $WEBAPP_ROOT && npx tsc --noEmit ``` If Phase A is not marked ✅ → stop and report. --- ## Phase B execution steps ### B1 — Read the plan Extract from `MIGRATION_PLAN.md` Phase B section: - Server Components list (RSC) - Client Components list (RCC) with reasons - Provider Wrappers needed ### B2 — Migrate Server Components (RSC) For each component in the RSC list — no directive needed, just ensure no client-only APIs are present: ```typescript // components/ConferenceCard.tsx — RSC (no directive) import { Conference } from '@/types/conference' interface Props { conference: Conference } export function ConferenceCard({ conference }: Props) { return (

{conference.title}

{conference.description}

) } ``` **Validation per RSC file:** ```bash # Confirm no client-only APIs leaked in grep -n "useState\|useEffect\|useRef\|onClick\|onChange\|window\.\|document\." \ path/to/component.tsx # Must return 0 matches ``` ### B3 — Migrate Client Components (RCC) For each component in the RCC list — add `'use client'` as the very first line: ```typescript 'use client' // components/ConferenceForm.tsx — RCC (has interactivity) import { useState } from 'react' import { useRouter } from 'next/navigation' export function ConferenceForm() { const [title, setTitle] = useState('') const router = useRouter() const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() // submit logic router.push('/conferences') } return (
setTitle(e.target.value)} />
) } ``` **Rules for RCC:** - `'use client'` must be the first line — before imports - All hooks remain unchanged (`useState`, `useEffect`, etc.) - Event handlers remain unchanged - `useRouter`, `usePathname`, `useSearchParams` come from `next/navigation` ### B4 — Extract Context Providers For each provider in the Provider Wrappers list: ```typescript // app/providers/{name}-provider.tsx — always 'use client' 'use client' import { createContext, useContext, useState } from 'react' // 1. Move context definition here from original file const ConferenceContext = createContext(null) // 2. Export the provider as a wrapper component export function ConferenceProvider({ children }: { children: React.ReactNode }) { const [state, setState] = useState(initialState) return ( {children} ) } // 3. Export the hook for consumption in RCC export function useConference() { const ctx = useContext(ConferenceContext) if (!ctx) throw new Error('useConference must be used within ConferenceProvider') return ctx } ``` Then import the provider in `app/layout.tsx` (which stays as RSC): ```typescript // app/layout.tsx — RSC, imports client provider import { ConferenceProvider } from './providers/conference-provider' export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ) } ``` ### B5 — Verify ```bash cd conference-manager/ms-conference-webapp # TypeScript check npx tsc --noEmit # Verify no RSC has client-only APIs without 'use client' grep -rL "use client" app/components/ --include="*.tsx" | \ xargs grep -l "useState\|useEffect\|onClick\|onChange" 2>/dev/null # Must return empty — any match is a missing 'use client' # Verify 'use client' is first line where present grep -rn "use client" app/ --include="*.tsx" | \ grep -v "^.*:1:'use client'" | grep -v "^.*:1:\"use client\"" # Must return empty — 'use client' not on line 1 is an error ``` --- ## Completion report ``` ✅ Phase B Complete — Component Migration Server Components (RSC): {count} files Client Components (RCC): {count} files Provider wrappers created: {count} files Files created/modified: - {list} TypeScript: ✅ 0 errors Ready for Phase C: react-to-nextjs-data-fetching ``` Update `MIGRATION_PLAN.md` marking Phase B items with ✅.