UNPKG

@oxyhq/services

Version:

OxyHQ Expo/React Native SDK — UI components, screens, and native features

609 lines (606 loc) 19.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = require("react"); var _reactNative = require("react-native"); var _index = require("../../components/index.js"); var _vectorIcons = require("@expo/vector-icons"); var _useI18n = require("../../hooks/useI18n.js"); var _useThemeStyles = require("../../hooks/useThemeStyles.js"); var _themeUtils = require("../../utils/themeUtils.js"); var _useColorScheme = require("../../hooks/useColorScheme.js"); var _theme = require("../../constants/theme.js"); var _OxyContext = require("../../context/OxyContext.js"); var _colorUtils = require("../../utils/colorUtils.js"); var _fonts = require("../../styles/fonts.js"); var _jsxRuntime = require("react/jsx-runtime"); const KarmaRewardsScreen = ({ goBack, theme }) => { const { t } = (0, _useI18n.useI18n)(); const { user, oxyServices, isAuthenticated } = (0, _OxyContext.useOxy)(); const [karmaTotal, setKarmaTotal] = (0, _react.useState)(0); const [isLoading, setIsLoading] = (0, _react.useState)(true); const normalizedTheme = (0, _themeUtils.normalizeTheme)(theme); const baseThemeStyles = (0, _useThemeStyles.useThemeStyles)(normalizedTheme); const colorScheme = (0, _useColorScheme.useColorScheme)(); const normalizedColorScheme = (0, _themeUtils.normalizeColorScheme)(colorScheme); const colors = _theme.Colors[normalizedColorScheme]; const themeStyles = (0, _react.useMemo)(() => ({ ...baseThemeStyles, primaryColor: '#d169e5' }), [baseThemeStyles]); (0, _react.useEffect)(() => { if (!user || !isAuthenticated) { setIsLoading(false); return; } setIsLoading(true); oxyServices.getUserKarmaTotal(user.id).then(data => { setKarmaTotal(data.total || 0); }).catch(() => { setKarmaTotal(0); }).finally(() => setIsLoading(false)); }, [user, isAuthenticated, oxyServices]); const achievements = (0, _react.useMemo)(() => [{ id: 'first-step', name: t('karma.achievements.firstStep') || 'First Step', description: t('karma.achievements.firstStepDesc') || 'Earned your first karma point', category: 'milestone', icon: 'footsteps', iconColor: '#8E8E93', unlocked: karmaTotal >= 1, rarity: 'common' }, { id: 'novice', name: t('karma.achievements.novice') || 'Novice', description: t('karma.achievements.noviceDesc') || 'Reached 10 karma points', category: 'milestone', icon: 'leaf', iconColor: '#34C759', unlocked: karmaTotal >= 10, rarity: 'common' }, { id: 'contributor', name: t('karma.achievements.contributor') || 'Contributor', description: t('karma.achievements.contributorDesc') || 'Reached 50 karma points', category: 'contribution', icon: 'account-group', iconColor: '#007AFF', unlocked: karmaTotal >= 50, rarity: 'common' }, { id: 'rising-star', name: t('karma.achievements.risingStar') || 'Rising Star', description: t('karma.achievements.risingStarDesc') || 'Reached 100 karma points', category: 'milestone', icon: 'star', iconColor: '#FF9500', unlocked: karmaTotal >= 100, rarity: 'rare' }, { id: 'early-adopter', name: t('karma.achievements.earlyAdopter') || 'Early Adopter', description: t('karma.achievements.earlyAdopterDesc') || 'Been part of the community from the start', category: 'special', icon: 'rocket', iconColor: '#AF52DE', unlocked: karmaTotal >= 200, rarity: 'rare' }, { id: 'community-hero', name: t('karma.achievements.communityHero') || 'Community Hero', description: t('karma.achievements.communityHeroDesc') || 'Reached 500 karma points', category: 'contribution', icon: 'shield', iconColor: '#FF2D55', unlocked: karmaTotal >= 500, rarity: 'epic' }, { id: 'legend', name: t('karma.achievements.legend') || 'Legend', description: t('karma.achievements.legendDesc') || 'Reached 1000 karma points', category: 'milestone', icon: 'trophy', iconColor: '#FFD700', unlocked: karmaTotal >= 1000, rarity: 'legendary' }, { id: 'phoenix', name: t('karma.achievements.phoenix') || 'Phoenix', description: t('karma.achievements.phoenixDesc') || 'Reached 2500 karma points', category: 'milestone', icon: 'flame', iconColor: '#FF3B30', unlocked: karmaTotal >= 2500, rarity: 'legendary' }, { id: 'unstoppable', name: t('karma.achievements.unstoppable') || 'Unstoppable', description: t('karma.achievements.unstoppableDesc') || 'Reached 5000 karma points', category: 'milestone', icon: 'infinite', iconColor: '#5E5CE6', unlocked: karmaTotal >= 5000, rarity: 'legendary' }, { id: 'bug-hunter', name: t('karma.achievements.bugHunter') || 'Bug Hunter', description: t('karma.achievements.bugHunterDesc') || 'Reported helpful bugs', category: 'contribution', icon: 'bug', iconColor: '#FF9500', unlocked: false, // TODO: Check actual bug reports rarity: 'rare' }, { id: 'helper', name: t('karma.achievements.helper') || 'Helper', description: t('karma.achievements.helperDesc') || 'Helped 10 users', category: 'contribution', icon: 'hand-left', iconColor: '#34C759', unlocked: false, // TODO: Check help actions rarity: 'common' }, { id: 'streak-master', name: t('karma.achievements.streakMaster') || 'Streak Master', description: t('karma.achievements.streakMasterDesc') || '7 day activity streak', category: 'streak', icon: 'flash', iconColor: '#FFD700', unlocked: false, // TODO: Check streak rarity: 'epic' }], [t, karmaTotal, colors]); const unlockedAchievements = achievements.filter(a => a.unlocked); const lockedAchievements = achievements.filter(a => !a.unlocked); const getRarityColor = rarity => { switch (rarity) { case 'legendary': return '#FFD700'; case 'epic': return '#AF52DE'; case 'rare': return '#007AFF'; default: return '#8E8E93'; } }; const getAchievementValue = achievement => { // Extract numeric value from achievement based on ID and unlocked state const valueMap = { 'first-step': 1, 'novice': 10, 'contributor': 50, 'rising-star': 100, 'early-adopter': 200, 'community-hero': 500, 'legend': 1000, 'phoenix': 2500, 'unstoppable': 5000, 'helper': 10, 'streak-master': 7 }; return valueMap[achievement.id] || null; }; const renderAchievement = achievement => { const rarityColor = getRarityColor(achievement.rarity); const isLocked = !achievement.unlocked; const achievementValue = getAchievementValue(achievement); // Two-tone colors: darker for borders/shadow, lighter for highlights // Use achievement iconColor for unlocked badges, gray for locked const baseColor = isLocked ? '#8E8E93' : achievement.iconColor || '#8E8E93'; const darkTone = (0, _colorUtils.darkenColor)(baseColor, 0.45); // Darker border/shadow (more contrast) const lightTone = (0, _colorUtils.lightenColor)(baseColor, 0.25); // Lighter highlight const mediumTone = baseColor; // Base color return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [styles.achievementCard, { backgroundColor: colors.card }], children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.badgeContainer, children: [!isLocked && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.badgeGlow, styles.badgeOrganic, { backgroundColor: darkTone, opacity: 0.3 }] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [styles.badgeMain, styles.badgeOrganic, { backgroundColor: isLocked ? '#E5E5EA' : mediumTone, borderColor: darkTone, borderWidth: 5, shadowColor: darkTone }], children: [!isLocked && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.badgeHighlight, { backgroundColor: lightTone }] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.badgeHighlightAccent, { backgroundColor: (0, _colorUtils.lightenColor)(lightTone, 0.1) }] })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.badgeIconContainer, children: isLocked ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: "lock-closed", size: 40, color: "#8E8E93" }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, { name: achievement.icon, size: 40, color: "#FFFFFF" }) }), achievementValue !== null && !isLocked && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.badgeValueContainer, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.badgeValueText, { color: lightTone, textShadowColor: darkTone }], children: achievementValue }) })] }), achievement.unlocked && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.rarityBadge, { backgroundColor: rarityColor, borderColor: (0, _colorUtils.darkenColor)(rarityColor, 0.4) }], children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: styles.rarityText, children: achievement.rarity[0].toUpperCase() }) })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.achievementName, { color: themeStyles.textColor, opacity: isLocked ? 0.5 : 1 }], children: achievement.name }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.achievementDescription, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#888888', opacity: isLocked ? 0.5 : 1 }], children: achievement.description })] }, achievement.id); }; if (!isAuthenticated) { return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [styles.container, { backgroundColor: themeStyles.backgroundColor }], children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index.Header, { title: t('karma.rewards.title') || 'Karma Rewards', subtitle: t('karma.rewards.subtitle') || 'Unlock special features and recognition', onBack: goBack, elevation: "subtle" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.centerContent, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.message, { color: themeStyles.textColor }], children: t('common.status.notSignedIn') || 'Not signed in' }) })] }); } return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [styles.container, { backgroundColor: themeStyles.backgroundColor }], children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index.Header, { title: t('karma.rewards.title') || 'Karma Rewards', subtitle: t('karma.rewards.subtitle') || 'Unlock special features and recognition', onBack: goBack, elevation: "subtle" }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, { contentContainerStyle: styles.contentContainer, showsVerticalScrollIndicator: false, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [styles.statsCard, { backgroundColor: colors.card }], children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.statsHeader, children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.currentKarma, { color: themeStyles.primaryColor }], children: karmaTotal }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.karmaLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#888888' }], children: t('karma.center.balance') || 'Karma Points' })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.achievementStats, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.achievementCount, { color: themeStyles.primaryColor }], children: unlockedAchievements.length }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.achievementCountLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#888888' }], children: t('karma.achievements.unlocked') || 'Achievements' })] })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: styles.progressBarContainer, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.progressBar, { backgroundColor: themeStyles.borderColor }], children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.progressBarFill, { width: `${unlockedAchievements.length / achievements.length * 100}%`, backgroundColor: themeStyles.primaryColor }] }) }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, { style: [styles.progressText, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#888888' }], children: [unlockedAchievements.length, " / ", achievements.length] })] })] }), unlockedAchievements.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.sectionTitle, { color: themeStyles.textColor }], children: t('karma.achievements.unlocked') || 'Unlocked Achievements' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.achievementsGrid, children: unlockedAchievements.map(achievement => renderAchievement(achievement)) })] }), lockedAchievements.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.sectionTitle, { color: themeStyles.textColor }], children: t('karma.achievements.locked') || 'Locked Achievements' }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.achievementsGrid, children: lockedAchievements.map(achievement => renderAchievement(achievement)) })] })] })] }); }; const styles = _reactNative.StyleSheet.create({ container: { flex: 1 }, contentContainer: { paddingHorizontal: 24, paddingTop: 20, paddingBottom: 40 }, centerContent: { flex: 1, justifyContent: 'center', alignItems: 'center' }, message: { fontSize: 16, textAlign: 'center' }, statsCard: { borderRadius: 18, padding: 20, marginBottom: 24 }, statsHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }, currentKarma: { fontSize: 36, fontWeight: _reactNative.Platform.OS === 'web' ? 'bold' : undefined, fontFamily: _fonts.fontFamilies.interBold, marginBottom: 4 }, achievementStats: { alignItems: 'flex-end' }, achievementCount: { fontSize: 36, fontWeight: _reactNative.Platform.OS === 'web' ? 'bold' : undefined, fontFamily: _fonts.fontFamilies.interBold, marginBottom: 4 }, achievementCountLabel: { fontSize: 14 }, karmaLabel: { fontSize: 14 }, progressBarContainer: { marginTop: 8 }, progressBar: { height: 8, borderRadius: 4, overflow: 'hidden', marginBottom: 8 }, progressBarFill: { height: '100%', borderRadius: 4 }, progressText: { fontSize: 12, textAlign: 'right' }, sectionTitle: { fontSize: 20, fontWeight: _reactNative.Platform.OS === 'web' ? '600' : undefined, fontFamily: _fonts.fontFamilies.interSemiBold, marginTop: 8 }, achievementsGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: 20, marginBottom: 24, justifyContent: 'space-between' }, achievementCard: { width: '47%', minWidth: 140, borderRadius: 20, padding: 20, paddingTop: 24, alignItems: 'center' }, badgeContainer: { alignItems: 'center', justifyContent: 'center', marginBottom: 12, position: 'relative', width: 120, height: 120 }, badgeGlow: { position: 'absolute', width: 135, height: 135, borderRadius: 67.5, shadowOffset: { width: 0, height: 6 }, shadowRadius: 15, shadowOpacity: 0.4, elevation: 10 }, badgeOrganic: { width: 120, height: 120, // More organic blob shape with varied border radius (like Duolingo) borderTopLeftRadius: 48, borderTopRightRadius: 52, borderBottomLeftRadius: 52, borderBottomRightRadius: 48, alignItems: 'center', justifyContent: 'center' }, badgeMain: { position: 'absolute', shadowOffset: { width: 0, height: 6 }, shadowRadius: 12, shadowOpacity: 0.5, elevation: 8 }, badgeHighlight: { position: 'absolute', top: 0, left: 0, right: 0, height: '50%', borderTopLeftRadius: 48, borderTopRightRadius: 52, opacity: 0.6 }, badgeHighlightAccent: { position: 'absolute', top: 0, left: 0, right: 0, height: '30%', borderTopLeftRadius: 48, borderTopRightRadius: 52, opacity: 0.3 }, badgeIconContainer: { position: 'absolute', top: 8, left: 0, right: 0, alignItems: 'center', justifyContent: 'flex-start', zIndex: 10, paddingTop: 12 }, badgeValueContainer: { position: 'absolute', bottom: 8, left: 0, right: 0, alignItems: 'center', justifyContent: 'center', zIndex: 10 }, badgeValueText: { fontSize: 32, fontWeight: 'bold', textShadowOffset: { width: 0, height: 2 }, textShadowRadius: 4, letterSpacing: -1 }, rarityBadge: { position: 'absolute', top: -6, right: -6, width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center', borderWidth: 3, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.4, shadowRadius: 4, elevation: 5 }, rarityText: { fontSize: 14, fontWeight: 'bold', color: '#FFFFFF' }, achievementName: { fontSize: 15, fontWeight: '700', textAlign: 'center', marginBottom: 6, marginTop: 4 }, achievementDescription: { fontSize: 11, textAlign: 'center', lineHeight: 15 } }); var _default = exports.default = KarmaRewardsScreen; //# sourceMappingURL=KarmaRewardsScreen.js.map