export function mobileAppRating(form: FormTs) {
// In-App Rating Prompt - Smart routing for app store reviews
// Demonstrates: EmojiRating, StarRating, ThumbRating, SuggestionChips, conditional flows, dynamic styling
// State for tracking flow
const showDetailedFeedback = form.state(false);
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: '🌟 Enjoying the App?',
computedValue: () => 'Your feedback means the world to us!',
customStyles: {
background: 'linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%)',
color: 'white',
padding: '20px',
borderRadius: '16px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Initial Mood Check (Quick)
// ============================================
const moodSection = form.addSubform('moodSection', {
customStyles: {
backgroundColor: '#f8fafc',
padding: '20px',
borderRadius: '12px',
textAlign: 'center'
}
});
moodSection.addRow(row => {
row.addEmojiRating('initialMood', {
label: 'How are you feeling about the app?',
preset: 'satisfaction',
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
// ============================================
// SECTION 2: Happy Path - Request Store Review
// ============================================
const happySection = form.addSubform('happySection', {
isVisible: () => {
const mood = moodSection.emojiRating('initialMood')?.value();
return mood === 'good' || mood === 'excellent';
},
customStyles: () => ({
backgroundColor: '#d1fae5',
padding: '20px',
borderRadius: '12px',
textAlign: 'center'
})
});
happySection.addRow(row => {
row.addTextPanel('happyMessage', {
label: '🎉 Awesome!',
computedValue: () => "We're thrilled you're enjoying the app! Would you mind taking a moment to rate us on the App Store? It really helps!",
customStyles: {
textAlign: 'center',
fontSize: '16px'
}
});
});
happySection.addRow(row => {
row.addStarRating('storeRatingPreview', {
label: 'How many stars would you give us?',
maxStars: 5,
size: 'xl',
alignment: 'center',
filledColor: '#fbbf24',
showConfettiOnMax: true
});
});
happySection.addRow(row => {
row.addThumbRating('goToStore', {
label: 'Ready to leave a review?',
showLabels: true,
upLabel: "Yes, I'll rate it!",
downLabel: 'Not right now',
alignment: 'center',
size: 'lg'
});
});
// Thank you for review intent
happySection.addRow(row => {
row.addTextPanel('thankYouReview', {
computedValue: () => "🙏 Thank you! Tap the button that appears to open the App Store.",
customStyles: {
backgroundColor: '#fef3c7',
padding: '12px',
borderRadius: '8px',
textAlign: 'center',
fontWeight: 'bold'
},
isVisible: () => happySection.thumbRating('goToStore')?.value() === 'up'
});
});
// ============================================
// SECTION 3: Unhappy Path - Capture Feedback
// ============================================
const unhappySection = form.addSubform('unhappySection', {
isVisible: () => {
const mood = moodSection.emojiRating('initialMood')?.value();
return mood === 'very-bad' || mood === 'bad' || mood === 'neutral';
},
customStyles: {
backgroundColor: '#fef3c7',
padding: '20px',
borderRadius: '12px'
}
});
unhappySection.addRow(row => {
row.addTextPanel('unhappyMessage', {
label: () => {
const mood = moodSection.emojiRating('initialMood')?.value();
if (mood === 'very-bad' || mood === 'bad') return '😔 We want to do better';
return '🤔 Help us improve';
},
computedValue: () => "We're sorry to hear that. Please tell us what's not working so we can fix it.",
customStyles: {
textAlign: 'center',
fontSize: '16px'
}
});
});
unhappySection.addRow(row => {
row.addSuggestionChips('issueCategories', {
label: 'What needs improvement?',
suggestions: [
{ id: 'bugs', name: '🐛 Bugs' },
{ id: 'slow', name: '🐢 Slow' },
{ id: 'confusing', name: '😕 Confusing' },
{ id: 'features', name: '✨ Features' },
{ id: 'design', name: '🎨 Design' },
{ id: 'crashes', name: '💥 Crashes' }
],
max: 3,
alignment: 'center'
});
});
unhappySection.addSpacer({ height: '16px' });
unhappySection.addRow(row => {
row.addTextarea('feedbackDetails', {
label: 'Tell us more (optional)',
placeholder: 'What would make the app better for you?',
rows: 3,
autoExpand: true
});
});
unhappySection.addRow(row => {
row.addCheckbox('contactMe', {
label: 'Contact me about this issue'
});
});
unhappySection.addRow(row => {
row.addEmail('contactEmail', {
label: 'Your email',
placeholder: 'you@email.com',
isRequired: () => unhappySection.checkbox('contactMe')?.value() === true,
isVisible: () => unhappySection.checkbox('contactMe')?.value() === true
});
});
// ============================================
// SECTION 4: Feature Suggestions (for neutral/good users)
// ============================================
const suggestionsSection = form.addSubform('suggestionsSection', {
title: 'Any suggestions?',
isVisible: () => {
const mood = moodSection.emojiRating('initialMood')?.value();
return mood === 'neutral' || mood === 'good';
},
customStyles: {
backgroundColor: '#f8fafc',
padding: '16px',
borderRadius: '12px',
marginTop: '12px'
}
});
suggestionsSection.addRow(row => {
row.addSuggestionChips('featureWishes', {
label: "What would make the app even better?",
suggestions: [
{ id: 'dark-mode', name: '🌙 Dark mode' },
{ id: 'widgets', name: '📱 Widgets' },
{ id: 'sync', name: '☁️ Better sync' },
{ id: 'offline', name: '📴 Offline mode' },
{ id: 'shortcuts', name: '⚡ Shortcuts' },
{ id: 'notifications', name: '🔔 Notifications' }
],
max: 2,
alignment: 'center'
});
});
// ============================================
// SECTION 5: Usage Context
// ============================================
const usageSection = form.addSubform('usageSection', {
isVisible: () => moodSection.emojiRating('initialMood')?.value() !== null,
customStyles: {
padding: '16px',
borderRadius: '8px',
border: '1px solid #e2e8f0',
marginTop: '12px'
}
});
usageSection.addRow(row => {
row.addDropdown('usageFrequency', {
label: 'How often do you use the app?',
options: [
{ id: 'daily', name: 'Daily' },
{ id: 'weekly', name: 'Few times a week' },
{ id: 'monthly', name: 'Few times a month' },
{ id: 'rarely', name: 'Rarely' },
{ id: 'new', name: 'Just started using it' }
],
placeholder: 'Select frequency'
}, '1fr');
row.addDropdown('favoriteFeature', {
label: 'Favorite feature?',
options: [
{ id: 'core', name: 'Core functionality' },
{ id: 'design', name: 'Clean design' },
{ id: 'speed', name: 'Speed/Performance' },
{ id: 'sync', name: 'Sync across devices' },
{ id: 'none', name: 'Nothing stands out' }
],
placeholder: 'Select feature'
}, '1fr');
});
// ============================================
// SUMMARY
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Feedback Summary',
isVisible: () => moodSection.emojiRating('initialMood')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const mood = moodSection.emojiRating('initialMood')?.value();
const storeIntent = happySection.thumbRating('goToStore')?.value();
const stars = happySection.starRating('storeRatingPreview')?.value();
const issues = unhappySection.suggestionChips('issueCategories')?.value() || [];
const wishes = suggestionsSection.suggestionChips('featureWishes')?.value() || [];
const contactRequested = unhappySection.checkbox('contactMe')?.value();
const moodLabels: Record<string, string> = {
'very-bad': '😢 Very Unhappy',
'bad': '😕 Unhappy',
'neutral': '😐 Neutral',
'good': '😊 Happy',
'excellent': '🤩 Love it!'
};
let summary = 'App Feedback\n';
summary += '═'.repeat(20) + '\n\n';
summary += `Feeling: ${moodLabels[mood || ''] || 'Not answered'}\n`;
if (stars) {
summary += `Star Rating: ${'★'.repeat(stars)}${'☆'.repeat(5 - stars)}\n`;
}
if (storeIntent === 'up') {
summary += '📱 Will leave App Store review\n';
}
if (issues.length > 0) {
summary += `\n⚠️ Issues: ${issues.join(', ')}\n`;
}
if (wishes.length > 0) {
summary += `\n✨ Wants: ${wishes.join(', ')}\n`;
}
if (contactRequested) {
summary += '\n📧 Contact requested';
}
return summary;
},
customStyles: {
padding: '16px',
borderRadius: '8px',
backgroundColor: '#f1f5f9',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '13px'
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: () => {
const mood = moodSection.emojiRating('initialMood')?.value();
if (mood === 'good' || mood === 'excellent') return 'Done';
return 'Send Feedback';
},
isVisible: () => moodSection.emojiRating('initialMood')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: () => {
const mood = moodSection.emojiRating('initialMood')?.value();
if (mood === 'good' || mood === 'excellent') return '💖 Thank You!';
return 'Thanks for the Feedback!';
},
message: () => {
const mood = moodSection.emojiRating('initialMood')?.value();
if (mood === 'good' || mood === 'excellent') {
return 'Your support means everything to us. Enjoy the app!';
}
return "We've received your feedback and will use it to make the app better. Thanks for helping us improve!";
}
});
}