Repository: novuhq/novu
File: apps/dashboard/src/components/welcome/inbox-framework-guide.tsx (TypeScript)

Code before:
        ?.replace(/YOUR_APP_ID/g, environmentIdentifier)
        ?.replace(/YOUR_APPLICATION_IDENTIFIER/g, environmentIdentifier)
        ?.replace(/YOUR_SUBSCRIBER_ID/g, subscriberId)
        ?.replace(/YOUR_PRIMARY_COLOR/g, primaryColor)
        ?.replace(/YOUR_FOREGROUND_COLOR/g, foregroundColor),
    })),
  };
}

export function InboxFrameworkGuide({
  currentEnvironment,
  subscriberId,
  primaryColor,
  foregroundColor,
}: InboxFrameworkGuideProps) {
  const track = useTelemetry();
  const [selectedFramework, setSelectedFramework] = useState<CliFramework | ManualFramework>(
    cliFrameworks.find((f) => f.selected) || cliFrameworks[0]
  );
  const [installationMethod, setInstallationMethod] = useState<'cli' | 'manual'>('cli');
  const [packageManager, setPackageManager] = useState<PackageManager>('npm');

  useEffect(() => {
    if (!currentEnvironment?.identifier || !subscriberId) return;

    const frameworks = installationMethod === 'cli' ? cliFrameworks : manualFrameworks;
    const updatedFrameworks = frameworks.map((framework) =>
      updateFrameworkCode(framework, currentEnvironment.identifier, subscriberId, primaryColor, foregroundColor)
    );

    setSelectedFramework(updatedFrameworks.find((f) => f.name === selectedFramework.name) || updatedFrameworks[0]);
  }, [
    currentEnvironment?.identifier,
    subscriberId,
    selectedFramework.name,
    primaryColor,
    foregroundColor,
    installationMethod,
  ]);

  useEffect(() => {
    if (['Remix', 'Native', 'Angular', 'JavaScript'].includes(selectedFramework.name)) {
      setInstallationMethod('manual');
    }
  }, [selectedFramework.name]);

  function handleFrameworkSelect(framework: CliFramework | ManualFramework) {
    track(TelemetryEvent.INBOX_FRAMEWORK_SELECTED, {
      framework: framework.name,
    });


Review comment (suggestion):
I think that we don't need to separate them to cli and manual frameworks as it creates a lot of unnecessary duplication, let's just have frameworks as they were before and just update the code example.
Basically you can copy the `commonInstallStep` from the `framework-cli.instructions.tsx` file and use it in the `framework-guides.instructions.tsx` file when the `installationMethod` is `cli`. So the code to get frameworks will be like:
```
const getFrameworks = (installationMethod: 'cli' | 'manual') => {
   return [{
    name: 'Next.js',
    icon: <RiNextjsFill className="h-8 w-8 text-black" />,
    selected: true,
    installSteps: installationMethod === 'cli' ? [commonCLIInstallStep('@novu/nextjs')] : [commonInstallStep('@novu/nextjs'), { ... }]
  }, ...]
}
```


Code after:
      code: step.code
        ?.replace(/YOUR_APP_ID/g, environmentIdentifier)
        ?.replace(/YOUR_APPLICATION_IDENTIFIER/g, environmentIdentifier)
        ?.replace(/YOUR_SUBSCRIBER_ID/g, subscriberId)
        ?.replace(/YOUR_PRIMARY_COLOR/g, primaryColor)
        ?.replace(/YOUR_FOREGROUND_COLOR/g, foregroundColor),
    })),
  };
}

export function InboxFrameworkGuide({
  currentEnvironment,
  subscriberId,
  primaryColor,
  foregroundColor,
}: InboxFrameworkGuideProps) {
  const track = useTelemetry();
  const [selectedFramework, setSelectedFramework] = useState<Framework>(
    getFrameworks('cli').find((f) => f.selected) || getFrameworks('cli')[0]
  );
  const [installationMethod, setInstallationMethod] = useState<'cli' | 'manual'>('cli');
  const [packageManager, setPackageManager] = useState<PackageManager>('npm');

  useEffect(() => {
    if (!currentEnvironment?.identifier || !subscriberId) return;

    const frameworks = getFrameworks(installationMethod);
    const updatedFrameworks = frameworks.map((framework) =>
      updateFrameworkCode(framework, currentEnvironment.identifier, subscriberId, primaryColor, foregroundColor)
    );

    setSelectedFramework(updatedFrameworks.find((f) => f.name === selectedFramework.name) || updatedFrameworks[0]);
  }, [
    currentEnvironment?.identifier,
    subscriberId,
    selectedFramework.name,
    primaryColor,
    foregroundColor,
    installationMethod,
  ]);

  useEffect(() => {
    if (['Remix', 'Native', 'Angular', 'JavaScript'].includes(selectedFramework.name)) {
      setInstallationMethod('manual');
    }
  }, [selectedFramework.name]);

  function handleFrameworkSelect(framework: Framework) {
    track(TelemetryEvent.INBOX_FRAMEWORK_SELECTED, {
      framework: framework.name,
    });