pbl-renderer.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. 'use client';
  2. import { useCallback } from 'react';
  3. import type { PBLContent } from '@/lib/types/stage';
  4. import type { PBLProjectConfig } from '@/lib/pbl/types';
  5. import { useStageStore } from '@/lib/store/stage';
  6. import { PBLRoleSelection } from './pbl/role-selection';
  7. import { PBLWorkspace } from './pbl/workspace';
  8. import { useI18n } from '@/lib/hooks/use-i18n';
  9. interface PBLRendererProps {
  10. readonly content: PBLContent;
  11. readonly mode: 'autonomous' | 'playback';
  12. readonly sceneId: string;
  13. }
  14. export function PBLRenderer({ content, mode: _mode, sceneId }: PBLRendererProps) {
  15. const { t } = useI18n();
  16. const { projectConfig } = content;
  17. const selectedRole = projectConfig?.selectedRole ?? null;
  18. const updateConfig = useCallback(
  19. (updatedConfig: PBLProjectConfig) => {
  20. const scenes = useStageStore.getState().scenes;
  21. const updatedScenes = scenes.map((scene) =>
  22. scene.id === sceneId
  23. ? {
  24. ...scene,
  25. content: { type: 'pbl' as const, projectConfig: updatedConfig },
  26. }
  27. : scene,
  28. );
  29. useStageStore.setState({ scenes: updatedScenes });
  30. },
  31. [sceneId],
  32. );
  33. const handleSelectRole = useCallback(
  34. (roleName: string) => {
  35. if (!projectConfig) return;
  36. const newConfig = { ...projectConfig, selectedRole: roleName };
  37. // Add Question Agent welcome message if chat is empty and active issue has questions
  38. const activeIssue = newConfig.issueboard.issues.find((i) => i.is_active);
  39. if (activeIssue?.generated_questions && newConfig.chat.messages.length === 0) {
  40. const welcomeMsg = t('pbl.chat.welcomeMessage', {
  41. title: activeIssue.title,
  42. questions: activeIssue.generated_questions,
  43. });
  44. newConfig.chat = {
  45. messages: [
  46. {
  47. id: `msg_welcome_${Date.now()}`,
  48. agent_name: activeIssue.question_agent_name,
  49. message: welcomeMsg,
  50. timestamp: Date.now(),
  51. read_by: [],
  52. },
  53. ],
  54. };
  55. }
  56. updateConfig(newConfig);
  57. },
  58. [projectConfig, updateConfig, t],
  59. );
  60. const handleReset = useCallback(() => {
  61. if (!projectConfig) return;
  62. // Reset all issues and re-activate the first one
  63. const resetIssues = projectConfig.issueboard.issues
  64. .map((i) => ({ ...i, is_done: false, is_active: false }))
  65. .sort((a, b) => a.index - b.index);
  66. if (resetIssues.length > 0) {
  67. resetIssues[0].is_active = true;
  68. }
  69. updateConfig({
  70. ...projectConfig,
  71. selectedRole: null,
  72. chat: { messages: [] },
  73. issueboard: {
  74. ...projectConfig.issueboard,
  75. issues: resetIssues,
  76. current_issue_id: resetIssues.length > 0 ? resetIssues[0].id : null,
  77. },
  78. });
  79. }, [projectConfig, updateConfig]);
  80. // Check for legacy format (old PBL with url/html)
  81. if (!projectConfig) {
  82. return (
  83. <div className="flex items-center justify-center h-full text-muted-foreground">
  84. <p>{t('pbl.legacyFormat')}</p>
  85. </div>
  86. );
  87. }
  88. // Check if project has been generated (has agents)
  89. if (projectConfig.agents.length === 0 && projectConfig.projectInfo.title === '') {
  90. return (
  91. <div className="flex items-center justify-center h-full text-muted-foreground">
  92. <p>{t('pbl.emptyProject')}</p>
  93. </div>
  94. );
  95. }
  96. // No role selected → show role selection
  97. if (!selectedRole) {
  98. return (
  99. <PBLRoleSelection
  100. projectInfo={projectConfig.projectInfo}
  101. agents={projectConfig.agents}
  102. onSelectRole={handleSelectRole}
  103. />
  104. );
  105. }
  106. // Role selected → show workspace
  107. return (
  108. <PBLWorkspace
  109. projectConfig={projectConfig}
  110. userRole={selectedRole}
  111. onConfigUpdate={updateConfig}
  112. onReset={handleReset}
  113. />
  114. );
  115. }