managarten/apps-archived/memoro/apps/mobile/features/rating/hooks/useRatingPrompt.ts
Till-JS 61d181fbc2 chore: archive inactive projects to apps-archived/
Move inactive projects out of active workspace:
- bauntown (community website)
- maerchenzauber (AI story generation)
- memoro (voice memo app)
- news (news aggregation)
- nutriphi (nutrition tracking)
- reader (reading app)
- uload (URL shortener)
- wisekeep (AI wisdom extraction)

Update CLAUDE.md documentation:
- Add presi to active projects
- Document archived projects section
- Update workspace configuration

Archived apps can be re-activated by moving back to apps/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 07:03:59 +01:00

98 lines
2.5 KiB
TypeScript

import { useState, useCallback } from 'react';
import { useRatingStore } from '../store/ratingStore';
import { useAnalytics } from '~/features/analytics';
// Milestones when to show the rating prompt
const RATING_MILESTONES = [5, 15, 50];
// Minimum days between prompts
const MIN_DAYS_BETWEEN_PROMPTS = 30;
/**
* Calculate days between two dates
*/
function daysBetween(date1: Date, date2: Date): number {
const oneDay = 24 * 60 * 60 * 1000; // milliseconds in one day
return Math.round(Math.abs((date1.getTime() - date2.getTime()) / oneDay));
}
/**
* Hook to manage rating prompt eligibility and display
*/
export const useRatingPrompt = () => {
const { track } = useAnalytics();
const [showPromptModal, setShowPromptModal] = useState(false);
const { memoCreatedCount, hasRatedApp, neverAskAgain, lastPromptDate, _hasHydrated } =
useRatingStore();
/**
* Check if we should show the rating prompt based on:
* - Memo count milestones
* - Previous rating status
* - Time since last prompt
*/
const checkShouldPrompt = useCallback((): boolean => {
// Don't check if store hasn't hydrated yet
if (!_hasHydrated) {
return false;
}
// Don't show if user already rated
if (hasRatedApp) {
return false;
}
// Don't show if user selected "never ask again"
if (neverAskAgain) {
return false;
}
// Check if we hit a milestone
const hitMilestone = RATING_MILESTONES.includes(memoCreatedCount);
if (!hitMilestone) {
return false;
}
// Check if enough time has passed since last prompt
if (lastPromptDate) {
const daysSinceLastPrompt = daysBetween(new Date(lastPromptDate), new Date());
if (daysSinceLastPrompt < MIN_DAYS_BETWEEN_PROMPTS) {
return false;
}
}
return true;
}, [memoCreatedCount, hasRatedApp, neverAskAgain, lastPromptDate, _hasHydrated]);
/**
* Trigger the rating prompt check
* Call this after significant positive actions (e.g., memo creation)
*/
const triggerPromptCheck = useCallback(() => {
const shouldShow = checkShouldPrompt();
if (shouldShow) {
setShowPromptModal(true);
track('rating_prompt_shown', {
memo_count: memoCreatedCount,
milestone: RATING_MILESTONES.find((m) => m === memoCreatedCount),
});
}
}, [checkShouldPrompt, memoCreatedCount, track]);
/**
* Close the rating prompt modal
*/
const closePrompt = useCallback(() => {
setShowPromptModal(false);
}, []);
return {
showPromptModal,
triggerPromptCheck,
closePrompt,
isEligible: checkShouldPrompt(),
currentMemoCount: memoCreatedCount,
};
};