From 973dd501fe8388b2f5801212c349d0d039c3dcc6 Mon Sep 17 00:00:00 2001 From: ajaysi Date: Wed, 22 Apr 2026 08:48:35 +0530 Subject: [PATCH] fix: PrimaryButton ref warning + research modal close race condition --- .planning/PROJECT.md | 46 ++++++ .planning/STATE.md | 40 +++++ .../PodcastDashboard/QuerySelection.tsx | 19 ++- .../PodcastMaker/ui/PrimaryButton.tsx | 11 +- .../components/UsageLimitRings.tsx | 13 +- .../src/components/shared/UsageDashboard.tsx | 155 ++++++++++++++++-- frontend/src/components/shared/UserBadge.tsx | 58 ++++--- frontend/src/contexts/SubscriptionContext.tsx | 5 + frontend/src/hooks/useSubscriptionGuard.ts | 10 ++ frontend/src/services/billingService.ts | 8 + frontend/src/types/billing.ts | 6 + temp_state.md | 46 ++++++ 12 files changed, 367 insertions(+), 50 deletions(-) create mode 100644 .planning/PROJECT.md create mode 100644 .planning/STATE.md create mode 100644 temp_state.md diff --git a/.planning/PROJECT.md b/.planning/PROJECT.md new file mode 100644 index 00000000..784ff160 --- /dev/null +++ b/.planning/PROJECT.md @@ -0,0 +1,46 @@ +# ALwrity Project + +## What This Is +ALwrity is an AI-powered content creation platform that helps users generate various types of content including podcasts, videos, blogs, and social media content. The platform features a React frontend and a FastAPI backend with onboarding workflows, API key management, and content generation capabilities. + +## Core Value +To provide an all-in-one AI content creation suite that simplifies the content production process for creators, marketers, and businesses. + +## Current Focus +Based on recent git commits, the team has been working on: +- Podcast production features (voice cloning, avatar generation, B-roll integration) +- Onboarding flow improvements +- Backend stability and debugging +- Frontend UI/UX enhancements + +## Requirements + +### Validated +- User authentication (Clerk) +- API key management for AI providers +- Basic podcast generation workflow +- File storage and media handling + +### Active +- Podcast script generation and editing +- Voice cloning and avatar creation +- B-roll scene rendering and integration +- Onboarding flow completion tracking +- API endpoint stability and debugging + +### Out of Scope +- Mobile applications (currently web-only) +- Enterprise team collaboration features +- Advanced analytics dashboard + +## Key Decisions +- Using FastAPI for backend performance +- React with Material-UI for frontend consistency +- Modular API design for extensibility +- Database-first approach for persistence + +## Constraints +- Must maintain backward compatibility with existing API +- Deployment targets include both development and production environments +- Must support multiple AI providers (OpenAI, HuggingFace, etc.) +- Budget-conscious resource usage for AI API calls \ No newline at end of file diff --git a/.planning/STATE.md b/.planning/STATE.md new file mode 100644 index 00000000..85645b42 --- /dev/null +++ b/.planning/STATE.md @@ -0,0 +1,40 @@ +# Project State + +## Project Reference +**Core Value**: ALwrity is an AI-powered content creation platform that helps users generate various types of content including podcasts, videos, blogs, and social media content. + +**Current Focus**: Based on recent development activity, the team is implementing Phase 2 of the WaveSpeed AI integration roadmap - Hyper-Personalization features for the Persona system, including voice training and avatar creation. + +## Current Position +**Phase**: 2 of 3 - Hyper-Personalization +**Plan**: 3 of 5 - Persona Avatar Creation & Integration +**Status**: In Progress - Working on avatar service implementation and frontend UI for avatar creation + +## Progress +Progress: [███████░░] 70% + +## Recent Decisions +1. **Avatar Service Architecture**: Decided to create a shared avatar service in backend/services/wavespeed/avatar/ for reuse across LinkedIn and Persona modules +2. **UI Framework**: Continuing with Material-UI (MUI) for consistent avatar creation interface +3. **Storage Strategy**: Using cloud storage for avatar assets with metadata tracking in PostgreSQL +4. **Generation Queue**: Implementing asynchronous processing for avatar generation to prevent API timeouts + +## Pending Todos +- [ ] Complete avatar generation API endpoints +- [ ] Implement avatar library management UI +- [ ] Add avatar preview functionality +- [ ] Create avatar upload/download capabilities +- [ ] Integrate avatar selection into Persona dashboard +- [ ] Add usage tracking and cost estimation for avatar generation +- [ ] Write comprehensive tests for avatar service +- [ ] Update documentation for avatar feature + +## Blockers/Concerns +- **WaveSpeed API Rate Limits**: Need to implement proper queuing and retry mechanisms +- **Storage Costs**: Avatar storage could become expensive at scale - need to implement cleanup policies +- **Generation Time**: Avatar generation can take 30-60 seconds - need to improve user experience during wait +- **Quality Consistency**: Ensuring generated avatars maintain consistent quality across different inputs + +Last session: 2026-04-21 07:02:08 +Stopped at: Session resumed, proceeding to discuss Phase 2 context +Resume file: [updated if applicable] diff --git a/frontend/src/components/PodcastMaker/PodcastDashboard/QuerySelection.tsx b/frontend/src/components/PodcastMaker/PodcastDashboard/QuerySelection.tsx index 34edea5c..e70aec58 100644 --- a/frontend/src/components/PodcastMaker/PodcastDashboard/QuerySelection.tsx +++ b/frontend/src/components/PodcastMaker/PodcastDashboard/QuerySelection.tsx @@ -87,17 +87,34 @@ export const QuerySelection: React.FC = ({ const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('sm')); const prevIsResearchingRef = useRef(isResearching); + const modalCloseTimeoutRef = useRef(null); // Close modal only when research actually completes (transitions from true to false) + // Prevent closing while research is in progress useEffect(() => { + // Clear any pending close timeout when research starts + if (researchStarted && isResearching) { + if (modalCloseTimeoutRef.current) { + clearTimeout(modalCloseTimeoutRef.current); + modalCloseTimeoutRef.current = null; + } + return; + } + const wasResearching = prevIsResearchingRef.current; const nowNotResearching = !isResearching; if (showResearchModal && researchStarted && wasResearching && nowNotResearching) { - setTimeout(() => setShowResearchModal(false), 1000); + modalCloseTimeoutRef.current = setTimeout(() => setShowResearchModal(false), 1000); } prevIsResearchingRef.current = isResearching; + + return () => { + if (modalCloseTimeoutRef.current) { + clearTimeout(modalCloseTimeoutRef.current); + } + }; }, [isResearching, showResearchModal, researchStarted]); // Progress message cycling diff --git a/frontend/src/components/PodcastMaker/ui/PrimaryButton.tsx b/frontend/src/components/PodcastMaker/ui/PrimaryButton.tsx index bb480206..2aea6ca0 100644 --- a/frontend/src/components/PodcastMaker/ui/PrimaryButton.tsx +++ b/frontend/src/components/PodcastMaker/ui/PrimaryButton.tsx @@ -14,7 +14,7 @@ interface PrimaryButtonProps { size?: "small" | "medium" | "large"; } -export const PrimaryButton: React.FC = ({ +export const PrimaryButton = React.forwardRef(({ children, onClick, disabled = false, @@ -25,7 +25,7 @@ export const PrimaryButton: React.FC = ({ ariaLabel, sx, size = "medium", -}) => { +}, ref) => { const sizeStyles = { small: { px: 1.5, py: 0.5, fontSize: "0.75rem" }, medium: { px: 3, py: 1, fontSize: "0.875rem" }, @@ -34,6 +34,7 @@ export const PrimaryButton: React.FC = ({ const button = (