Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { useIdeationStore } from '@/store/ideation-store';
import { useAppStore } from '@/store/app-store';
import { useGenerateIdeationSuggestions } from '@/hooks/mutations';
import { toast } from 'sonner';
import { useNavigate } from '@tanstack/react-router';
import type { IdeaCategory, IdeationPrompt } from '@automaker/types';

interface PromptListProps {
Expand All @@ -24,10 +23,8 @@ export function PromptList({ category, onBack }: PromptListProps) {
const generationJobs = useIdeationStore((s) => s.generationJobs);
const setMode = useIdeationStore((s) => s.setMode);
const addGenerationJob = useIdeationStore((s) => s.addGenerationJob);
const updateJobStatus = useIdeationStore((s) => s.updateJobStatus);
const [loadingPromptId, setLoadingPromptId] = useState<string | null>(null);
const [startedPrompts, setStartedPrompts] = useState<Set<string>>(new Set());
const navigate = useNavigate();

// React Query mutation
const generateMutation = useGenerateIdeationSuggestions(currentProject?.path ?? '');
Expand Down Expand Up @@ -72,27 +69,13 @@ export function PromptList({ category, onBack }: PromptListProps) {
toast.info(`Generating ideas for "${prompt.title}"...`);
setMode('dashboard');

// Start mutation - onSuccess/onError are handled at the hook level to ensure
// they fire even after this component unmounts (which happens due to setMode above)
generateMutation.mutate(
{ promptId: prompt.id, category },
{ promptId: prompt.id, category, jobId, promptTitle: prompt.title },
{
onSuccess: (data) => {
updateJobStatus(jobId, 'ready', data.suggestions);
toast.success(`Generated ${data.suggestions.length} ideas for "${prompt.title}"`, {
duration: 10000,
action: {
label: 'View Ideas',
onClick: () => {
setMode('dashboard');
navigate({ to: '/ideation' });
},
},
});
setLoadingPromptId(null);
},
onError: (error) => {
console.error('Failed to generate suggestions:', error);
updateJobStatus(jobId, 'error', undefined, error.message);
toast.error(error.message);
// Optional: reset local loading state if component is still mounted
onSettled: () => {
setLoadingPromptId(null);
},
}
Expand Down
38 changes: 33 additions & 5 deletions apps/ui/src/hooks/mutations/use-ideation-mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,32 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
import { getElectronAPI } from '@/lib/electron';
import { queryKeys } from '@/lib/query-keys';
import { toast } from 'sonner';
import type { IdeaCategory, IdeaSuggestion } from '@automaker/types';
import type { IdeaCategory, AnalysisSuggestion } from '@automaker/types';
import { useIdeationStore } from '@/store/ideation-store';

/**
* Input for generating ideation suggestions
*/
interface GenerateSuggestionsInput {
promptId: string;
category: IdeaCategory;
/** Job ID for tracking generation progress - used to update job status on completion */
jobId: string;
/** Prompt title for toast notifications */
promptTitle: string;
}

/**
* Result from generating suggestions
*/
interface GenerateSuggestionsResult {
suggestions: IdeaSuggestion[];
suggestions: AnalysisSuggestion[];
promptId: string;
category: IdeaCategory;
/** Job ID passed through for onSuccess handler */
jobId: string;
/** Prompt title passed through for toast notifications */
promptTitle: string;
}

/**
Expand Down Expand Up @@ -52,7 +61,7 @@ export function useGenerateIdeationSuggestions(projectPath: string) {

return useMutation({
mutationFn: async (input: GenerateSuggestionsInput): Promise<GenerateSuggestionsResult> => {
const { promptId, category } = input;
const { promptId, category, jobId, promptTitle } = input;

const api = getElectronAPI();
if (!api.ideation?.generateSuggestions) {
Expand All @@ -69,14 +78,33 @@ export function useGenerateIdeationSuggestions(projectPath: string) {
suggestions: result.suggestions ?? [],
promptId,
category,
jobId,
promptTitle,
};
},
onSuccess: () => {
onSuccess: (data) => {
// Update job status in Zustand store - this runs even if the component unmounts
// Using getState() to access store directly without hooks (safe in callbacks)
const updateJobStatus = useIdeationStore.getState().updateJobStatus;
updateJobStatus(data.jobId, 'ready', data.suggestions);

// Show success toast
toast.success(`Generated ${data.suggestions.length} ideas for "${data.promptTitle}"`, {
duration: 10000,
});

// Invalidate ideation ideas cache
queryClient.invalidateQueries({
queryKey: queryKeys.ideation.ideas(projectPath),
});
},
// Toast notifications are handled by the component since it has access to prompt title
onError: (error, variables) => {
// Update job status to error - this runs even if the component unmounts
const updateJobStatus = useIdeationStore.getState().updateJobStatus;
updateJobStatus(variables.jobId, 'error', undefined, error.message);

// Show error toast
toast.error(`Failed to generate ideas: ${error.message}`);
},
});
}