File size: 4,963 Bytes
bcce530
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Imports removed as icons are now strings

interface Prompt {
    id: string
    totalRuns: number
    starsCount: number
    remixesCount: number
    createdAt: Date
    framework?: string | null
    description?: string | null
    schema?: any
}

export interface Badge {
    id: string
    label: string
    icon: string
    color: string
    description: string
}

export const BADGE_DEFINITIONS: Record<string, Badge> = {
    HOT: {
        id: 'HOT',
        label: 'Hot',
        icon: 'Flame',
        color: 'orange',
        description: 'Trending this week',
    },
    VIRAL: {
        id: 'VIRAL',
        label: 'Viral',
        icon: 'Rocket',
        color: 'purple',
        description: '10,000+ total runs',
    },
    FEATURED: {
        id: 'FEATURED',
        label: 'Featured',
        icon: 'Star',
        color: 'yellow',
        description: 'Staff pick',
    },
    TOP_RATED: {
        id: 'TOP_RATED',
        label: 'Top Rated',
        icon: 'Trophy',
        color: 'gold',
        description: 'Highly starred',
    },
    WELL_DOCUMENTED: {
        id: 'WELL_DOCUMENTED',
        label: 'Well Documented',
        icon: '',
        color: 'blue',
        description: 'Complete documentation and examples',
    },
    FRAMEWORK: {
        id: 'FRAMEWORK',
        label: 'Framework',
        icon: '',
        color: 'green',
        description: 'Uses structured framework',
    },
    BATTLE_TESTED: {
        id: 'BATTLE_TESTED',
        label: 'Battle Tested',
        icon: '',
        color: 'teal',
        description: '1,000+ runs with high quality',
    },
    POPULAR: {
        id: 'POPULAR',
        label: 'Popular',
        icon: '',
        color: 'red',
        description: '100+ stars',
    },
    RISING: {
        id: 'RISING',
        label: 'Rising',
        icon: '',
        color: 'cyan',
        description: 'Fast growing engagement',
    },
    NEW: {
        id: 'NEW',
        label: 'New',
        icon: '',
        color: 'indigo',
        description: 'Created within last 7 days',
    },
}

/**
 * Calculate which badges a prompt should have
 */
export function calculateBadges(prompt: Prompt, allPrompts: Prompt[] = []): string[] {
    const badges: string[] = []

    // NEW - Created within last 7 days
    const daysSinceCreation = (Date.now() - prompt.createdAt.getTime()) / (1000 * 60 * 60 * 24)
    if (daysSinceCreation <= 7) {
        badges.push('NEW')
    }

    // VIRAL - 10,000+ runs
    if (prompt.totalRuns >= 10000) {
        badges.push('VIRAL')
    }

    // BATTLE_TESTED - 1,000+ runs
    if (prompt.totalRuns >= 1000) {
        badges.push('BATTLE_TESTED')
    }

    // POPULAR - 100+ stars
    if (prompt.starsCount >= 100) {
        badges.push('POPULAR')
    }

    // TOP_RATED - Top 10% by stars
    if (allPrompts.length > 0) {
        const sorted = [...allPrompts].sort((a, b) => b.starsCount - a.starsCount)
        const topThreshold = sorted[Math.floor(sorted.length * 0.1)]?.starsCount || 0
        if (prompt.starsCount >= topThreshold && prompt.starsCount > 20) {
            badges.push('TOP_RATED')
        }
    }

    // FRAMEWORK - Uses structured framework
    if (prompt.framework) {
        badges.push('FRAMEWORK')
    }

    // WELL_DOCUMENTED - Has description and schema with multiple variables
    const hasDescription = prompt.description && prompt.description.length > 50
    const hasSchema = prompt.schema?.variables?.length >= 3
    if (hasDescription && hasSchema) {
        badges.push('WELL_DOCUMENTED')
    }

    // HOT - Trending (simplified: created in last 14 days + good engagement)
    if (daysSinceCreation <= 14 && prompt.totalRuns >= 100 && prompt.starsCount >= 10) {
        badges.push('HOT')
    }

    // RISING - Fast growth (created recently + high engagement rate)
    if (daysSinceCreation <= 30 && daysSinceCreation > 7) {
        const runsPerDay = prompt.totalRuns / daysSinceCreation
        if (runsPerDay >= 10) {
            badges.push('RISING')
        }
    }

    return badges
}

/**
 * Get badge details
 */
export function getBadge(id: string): Badge | undefined {
    return BADGE_DEFINITIONS[id]
}

/**
 * Get all badge definitions
 */
export function getAllBadges(): Badge[] {
    return Object.values(BADGE_DEFINITIONS)
}

/**
 * Sort badges by priority for display
 */
export function sortBadges(badgeIds: string[]): string[] {
    const priority: Record<string, number> = {
        FEATURED: 1,
        VIRAL: 2,
        HOT: 3,
        RISING: 4,
        TOP_RATED: 5,
        BATTLE_TESTED: 6,
        POPULAR: 7,
        FRAMEWORK: 8,
        WELL_DOCUMENTED: 9,
        NEW: 10,
    }

    return badgeIds.sort((a, b) => (priority[a] || 999) - (priority[b] || 999))
}

/**
 * Manually award FEATURED badge (admin only)
 */
export function awardFeaturedBadge(promptId: string): string[] {
    // This would update the database
    // For now, just return the badge
    return ['FEATURED']
}