Skip to content

Commit ff92d18

Browse files
committed
feat: implement top-up minutes feature and enhance account management
- Introduced a new `TopUpMinutes` component for users to purchase additional transcription minutes. - Updated the `AccountData` component to include functionality for topping up minutes alongside tokens. - Enhanced API routes to handle top-up minutes transactions, including Stripe integration for payment processing. - Improved user experience by providing clear feedback on successful top-ups and error handling. - Updated relevant database schema and API responses to support the new minutes top-up feature.
1 parent d028866 commit ff92d18

File tree

16 files changed

+839
-253
lines changed

16 files changed

+839
-253
lines changed

packages/mobile/components/usage-status.tsx

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import React, { useState, useEffect } from 'react';
2-
import { View, StyleSheet, ActivityIndicator, Platform, TouchableOpacity, Linking } from 'react-native';
2+
import {
3+
View,
4+
StyleSheet,
5+
ActivityIndicator,
6+
Platform,
7+
TouchableOpacity,
8+
Linking,
9+
} from 'react-native';
310
import { useAuth } from '@clerk/clerk-expo';
411
import { MaterialIcons } from '@expo/vector-icons';
512
import { ThemedView } from './ThemedView';
@@ -16,6 +23,8 @@ type UsageData = {
1623
maxTokenUsage: number;
1724
subscriptionStatus: string;
1825
tier: string;
26+
// Note: audioTranscriptionMinutes and maxAudioTranscriptionMinutes are intentionally
27+
// excluded from the mobile app display for now, even if present in the API response
1928
};
2029

2130
export function UsageStatus({ compact = false }: UsageStatusProps) {
@@ -30,17 +39,17 @@ export function UsageStatus({ compact = false }: UsageStatusProps) {
3039
try {
3140
const token = await getToken();
3241
if (!token) {
33-
setError("Authentication required");
42+
setError('Authentication required');
3443
setLoading(false);
3544
return;
3645
}
3746

3847
const response = await fetch(`${API_URL}/api/usage`, {
3948
method: 'GET',
4049
headers: {
41-
'Authorization': `Bearer ${token}`,
42-
'Content-Type': 'application/json'
43-
}
50+
Authorization: `Bearer ${token}`,
51+
'Content-Type': 'application/json',
52+
},
4453
});
4554

4655
if (!response.ok) {
@@ -51,8 +60,8 @@ export function UsageStatus({ compact = false }: UsageStatusProps) {
5160
setUsageData(data);
5261
setLoading(false);
5362
} catch (err) {
54-
console.error("Error fetching usage info:", err);
55-
setError("Could not load usage information");
63+
console.error('Error fetching usage info:', err);
64+
setError('Could not load usage information');
5665
setLoading(false);
5766
}
5867
}
@@ -62,16 +71,24 @@ export function UsageStatus({ compact = false }: UsageStatusProps) {
6271

6372
if (loading) {
6473
return (
65-
<ThemedView variant="elevated" style={[styles.card, compact && styles.compactCard]}>
74+
<ThemedView
75+
variant="elevated"
76+
style={[styles.card, compact && styles.compactCard]}
77+
>
6678
<ActivityIndicator size="small" color={primaryColor} />
67-
<ThemedText style={{ marginTop: 8 }}>Loading usage information...</ThemedText>
79+
<ThemedText style={{ marginTop: 8 }}>
80+
Loading usage information...
81+
</ThemedText>
6882
</ThemedView>
6983
);
7084
}
7185

7286
if (error) {
7387
return (
74-
<ThemedView variant="elevated" style={[styles.card, compact && styles.compactCard]}>
88+
<ThemedView
89+
variant="elevated"
90+
style={[styles.card, compact && styles.compactCard]}
91+
>
7592
<MaterialIcons name="error-outline" size={24} color="#E53E3E" />
7693
<ThemedText style={{ marginTop: 8 }}>{error}</ThemedText>
7794
</ThemedView>
@@ -82,7 +99,7 @@ export function UsageStatus({ compact = false }: UsageStatusProps) {
8299
const getPlanDisplay = (plan: string) => {
83100
switch (plan?.toLowerCase()) {
84101
case 'free':
85-
return 'Legacy Plan';
102+
return 'Free Plan';
86103
case 'monthly':
87104
return 'Monthly Subscription';
88105
case 'yearly':
@@ -93,19 +110,20 @@ export function UsageStatus({ compact = false }: UsageStatusProps) {
93110
};
94111

95112
return (
96-
<ThemedView variant="elevated" style={[styles.card, compact && styles.compactCard]}>
113+
<ThemedView
114+
variant="elevated"
115+
style={[styles.card, compact && styles.compactCard]}
116+
>
97117
<View style={styles.planInfo}>
98-
<MaterialIcons
99-
name="star"
100-
size={24}
101-
color={primaryColor}
102-
/>
118+
<MaterialIcons name="star" size={24} color={primaryColor} />
103119
<View style={styles.planDetails}>
104120
<ThemedText type="defaultSemiBold">
105121
{getPlanDisplay(usageData?.tier || 'free')}
106122
</ThemedText>
107123
<ThemedText colorName="textSecondary" type="caption">
108-
{usageData?.subscriptionStatus === 'active' ? 'Active Account' : 'Free Usage'}
124+
{usageData?.subscriptionStatus === 'active'
125+
? 'Active Account'
126+
: 'Free Usage'}
109127
</ThemedText>
110128
</View>
111129
</View>
@@ -116,14 +134,17 @@ export function UsageStatus({ compact = false }: UsageStatusProps) {
116134
Usage: {usageData.tokenUsage} / {usageData.maxTokenUsage} tokens
117135
</ThemedText>
118136
<View style={styles.usageBar}>
119-
<View
137+
<View
120138
style={[
121-
styles.usageProgress,
122-
{
123-
width: `${Math.min(100, (usageData.tokenUsage / usageData.maxTokenUsage) * 100)}%`,
124-
backgroundColor: primaryColor
125-
}
126-
]}
139+
styles.usageProgress,
140+
{
141+
width: `${Math.min(
142+
100,
143+
(usageData.tokenUsage / usageData.maxTokenUsage) * 100
144+
)}%`,
145+
backgroundColor: primaryColor,
146+
},
147+
]}
127148
/>
128149
</View>
129150
</View>
@@ -211,4 +232,4 @@ const styles = StyleSheet.create({
211232
color: '#FFFFFF',
212233
letterSpacing: 0.2,
213234
},
214-
});
235+
});

packages/plugin/views/assistant/view.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ function AssistantContent({
196196
if (!usageData) return false;
197197

198198
const isFreeTier =
199-
usageData.currentPlan === "Legacy Plan" ||
199+
usageData.currentPlan === "Free Plan" ||
200200
usageData.currentPlan === "Free" ||
201201
usageData.maxTokenUsage === 100000;
202202

0 commit comments

Comments
 (0)