Changeset a6e33d1
- Timestamp:
- 07/02/26 23:35:59 (3 days ago)
- Branches:
- main
- Parents:
- 3ae4bab
- Files:
-
- 3 added
- 4 edited
-
ChapterX.API/Controllers/AISuggestionsController.cs (modified) (2 diffs)
-
ChapterX.Application/AISuggestion/Queries/GetByChapterHandler.cs (added)
-
ChapterX.Application/AISuggestion/Queries/GetByChapterRequest.cs (added)
-
ChapterX.Application/AISuggestion/Queries/GetByChapterResponse.cs (added)
-
ChapterX.Infrastructure/Repositories/AISuggestionRepository.cs (modified) (1 diff)
-
chapterx-frontend/src/components/writer/AISuggestionPanel.tsx (modified) (2 diffs)
-
chapterx-frontend/src/store/storyStore.ts (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
ChapterX.API/Controllers/AISuggestionsController.cs
r3ae4bab ra6e33d1 5 5 using Microsoft.AspNetCore.Mvc; 6 6 using Microsoft.Extensions.Logging; 7 using System.Linq; 7 8 8 9 namespace ChapterX.API.Controllers … … 37 38 var response = await _mediator.Send(new GetRequest(id)); 38 39 return Ok(response); 40 } 41 42 [HttpGet("chapter/{chapterId:int}")] 43 [AllowAnonymous] 44 public async Task<ActionResult> GetByChapter(int chapterId) 45 { 46 _logger.LogInformation("Fetching AI suggestions for ChapterId: {ChapterId}", chapterId); 47 var response = await _mediator.Send(new GetByChapterRequest(chapterId)); 48 var result = response.AISuggestions.Select(s => new 49 { 50 id = s.Id, 51 originalText = s.OriginalText, 52 suggestedText = s.SuggestedText, 53 accepted = s.Accepted, 54 createdAt = s.CreatedAt, 55 appliedAt = s.AppliedAt, 56 storyId = s.StoryId, 57 suggestionTypes = s.SuggestionTypes.Select(t => t.SuggestionTypeValue), 58 }); 59 return Ok(result); 39 60 } 40 61 -
ChapterX.Infrastructure/Repositories/AISuggestionRepository.cs
r3ae4bab ra6e33d1 21 21 { 22 22 return await _dbSet 23 .Where(a => a.StoryId == chapterId) 23 .Include(a => a.SuggestionTypes) 24 .Where(a => a.NeedApprovals.Any(na => na.ChapterId == chapterId)) 24 25 .ToListAsync(cancellationToken); 25 26 } -
chapterx-frontend/src/components/writer/AISuggestionPanel.tsx
r3ae4bab ra6e33d1 100 100 } 101 101 102 export const AISuggestionPanel: React.FC<AISuggestionPanelProps> = ({ chapterId , storyId}) => {102 export const AISuggestionPanel: React.FC<AISuggestionPanelProps> = ({ chapterId }) => { 103 103 const { aiSuggestions, acceptSuggestion, rejectSuggestion, fetchSuggestions } = useStoryStore() 104 104 const { addToast } = useUIStore() … … 108 108 useEffect(() => { 109 109 setLoading(true) 110 fetchSuggestions( ).finally(() => setLoading(false))110 fetchSuggestions(chapterId).finally(() => setLoading(false)) 111 111 }, [chapterId]) 112 112 113 // Filter by storyId if available (backend), else fall back to chapterId (mock) 114 const chapterSuggestions = aiSuggestions.filter(s => 115 storyId ? (s as any).story_id === storyId : s.chapter_id === chapterId 116 ) 113 // Backend already scopes results to this chapter via NEED_APPROVAL 114 const chapterSuggestions = aiSuggestions 117 115 const pending = chapterSuggestions.filter(s => s.accepted === null) 118 116 const accepted = chapterSuggestions.filter(s => s.accepted === true) -
chapterx-frontend/src/store/storyStore.ts
r3ae4bab ra6e33d1 7 7 Collaboration, 8 8 AISuggestion, 9 SuggestionType, 9 10 Genre, 10 11 ReadingList, … … 105 106 106 107 // AI Suggestion actions 107 fetchSuggestions: ( ) => Promise<void>108 fetchSuggestions: (chapterId: number) => Promise<void> 108 109 acceptSuggestion: (id: number) => Promise<void> 109 110 rejectSuggestion: (id: number) => Promise<void> … … 434 435 }, 435 436 436 fetchSuggestions: async ( ) => {437 try { 438 const res = await axios.get(`${API}/aisuggestions `)439 const data = res.data.aiSuggestions ?? res.data437 fetchSuggestions: async (chapterId) => { 438 try { 439 const res = await axios.get(`${API}/aisuggestions/chapter/${chapterId}`) 440 const data: any[] = res.data ?? [] 440 441 const mapped: AISuggestion[] = data.map((s: any) => ({ 441 442 suggestion_id: s.id, 442 chapter_id: s.storyId,443 chapter_id: chapterId, 443 444 story_id: s.storyId, 444 445 original_text: s.originalText, 445 446 suggested_text: s.suggestedText, 446 suggestion_type: 'style' as const,447 suggestion_type: (s.suggestionTypes?.[0] ?? 'style') as SuggestionType, 447 448 accepted: s.accepted === true ? true : s.accepted === false ? false : null, 448 449 applied_at: s.appliedAt ?? undefined, … … 471 472 suggestedText: s.suggested_text, 472 473 accepted: true, 473 } )474 }, { headers: getAuthHeaders() }) 474 475 } catch { 475 476 // keep optimistic update even if backend fails … … 491 492 suggestedText: s.suggested_text, 492 493 accepted: false, 493 } )494 }, { headers: getAuthHeaders() }) 494 495 } catch { 495 496 // keep optimistic update even if backend fails … … 502 503 set(state => ({ aiSuggestions: [...state.aiSuggestions, { ...suggestion, suggestion_id: tempId }] })) 503 504 try { 504 const res = await axios.post( '${API}/aisuggestions', {505 const res = await axios.post(`${API}/aisuggestions`, { 505 506 originalText: suggestion.original_text, 506 507 suggestedText: suggestion.suggested_text, 507 508 storyId: suggestion.chapter_id, 508 } )509 }, { headers: getAuthHeaders() }) 509 510 const newId = res.data.id ?? tempId 510 511 set(state => ({
Note:
See TracChangeset
for help on using the changeset viewer.
