diff --git a/app/(protected)/(tabs)/index.tsx b/app/(protected)/(tabs)/index.tsx index acd664c..4bc76a7 100644 --- a/app/(protected)/(tabs)/index.tsx +++ b/app/(protected)/(tabs)/index.tsx @@ -375,14 +375,6 @@ export default function Index() { outputRange: ["0deg", "360deg"], }); - const [_rawData, _loading, _error, run] = useAuthFetch( - "/users/user-full", - { method: "GET" }, - { manual: true, useCache: false }, - ); - useEffect(() => { - run().catch(() => {}); - }, [run]); return ( {/* Grid */} diff --git a/app/(protected)/(tabs)/settings.tsx b/app/(protected)/(tabs)/settings.tsx index 217e637..fee4857 100644 --- a/app/(protected)/(tabs)/settings.tsx +++ b/app/(protected)/(tabs)/settings.tsx @@ -1,7 +1,7 @@ import { BtnText, Button } from "@/components/button"; import { Image, StyleSheet, Text, View } from "react-native"; import { useTheme } from "@/lib/theme/context"; -import { Eye, Globe, Heart, MessageCircle, Moon, User } from "lucide-react-native"; +import { Eye, Gem, Globe, Heart, MessageCircle, Moon, User } from "lucide-react-native"; import { router } from "expo-router"; import { useAuth } from "@/lib/auth/AuthProvider"; import { createT } from "@/i18n"; @@ -52,6 +52,14 @@ export default function SettingsScreen() { textColor={theme.text} href="/settings/apperance" /> + void; +}) { + const { theme } = useTheme(); + return ( + + onChange("monthly")} + activeOpacity={0.8} + > + + Monthly + + + onChange("yearly")} + activeOpacity={0.8} + > + + Yearly + + {value === "yearly" && ( + + –17% + + )} + + + ); +} + +// ─── Plan Card ──────────────────────────────────────────────────────────────── + +function PlanCard({ + plan, + billing, + onSubscribe, +}: { + plan: Plan; + billing: BillingCycle; + onSubscribe: () => void; +}) { + const { theme } = useTheme(); + const price = billing === "monthly" ? plan.monthlyPrice : plan.yearlyPrice; + const isHighlight = plan.highlight; + + const cardBg = isHighlight ? theme.primary : theme.background; + const textColor = isHighlight ? "#fff" : theme.text; + const mutedColor = isHighlight ? "rgba(255,255,255,0.6)" : theme.accent; + const dividerColor = isHighlight ? "rgba(255,255,255,0.15)" : theme.accent + "22"; + const btnBg = isHighlight ? "#fff" : theme.primary; + const btnTextColor = isHighlight ? theme.primary : "#fff"; + + const whole = Math.floor(price); + const cents = (price % 1).toFixed(2).slice(1); + + return ( + + {/* Badge */} + {plan.badge ? ( + + + {plan.badge} + + + ) : ( + + )} + + {/* Tier */} + {plan.tier} + + {/* Name */} + + {plan.name} + + {plan.nameItalic} + + + + {plan.tagline} + + + + {/* Price + CTA */} + + + + Subscribe + + + + + $ + + {whole} + + + + {cents} + + /mo + + + + + + + {/* Features */} + + {plan.features.map((f, i) => ( + + + ✓ + + + {f} + + + ))} + + + ); +} + +// ─── Pagination Dots ────────────────────────────────────────────────────────── + +function PaginationDots({ total, active }: { total: number; active: number }) { + const { theme } = useTheme(); + return ( + + {Array.from({ length: total }).map((_, i) => ( + + ))} + + ); +} + +// ─── Main Screen ────────────────────────────────────────────────────────────── + +export default function SubscriptionPlans() { + const { theme } = useTheme(); + const [billing, setBilling] = useState("monthly"); + const [activeIndex, setActiveIndex] = useState(1); + const flatListRef = useRef(null); + + const handleScroll = (e: NativeSyntheticEvent) => { + const index = Math.round(e.nativeEvent.contentOffset.x / (CARD_WIDTH + CARD_GAP)); + setActiveIndex(Math.max(0, Math.min(index, PLANS.length - 1))); + }; + + return ( + + {/* Header */} + + + Choose your plan + + + Upgrade or downgrade at any time. + + + + {/* Toggle */} + + + + + {/* Cards — peek layout */} + p.id} + horizontal + showsHorizontalScrollIndicator={false} + snapToInterval={CARD_WIDTH + CARD_GAP} + snapToAlignment="start" + decelerationRate="fast" + contentContainerStyle={{ + paddingHorizontal: SIDE_PADDING, + paddingVertical: 20, + gap: CARD_GAP, + }} + initialScrollIndex={1} + getItemLayout={(_, index) => ({ + length: CARD_WIDTH + CARD_GAP, + offset: (CARD_WIDTH + CARD_GAP) * index, + index, + })} + onScroll={handleScroll} + scrollEventThrottle={16} + renderItem={({ item }) => ( + {}} /> + )} + /> + + {/* Dots */} + + + + Cancel anytime · No hidden fees + + + ); +} + +// ─── Styles ─────────────────────────────────────────────────────────────────── + +const styles = StyleSheet.create({ + safe: { flex: 1 }, + + header: { + paddingHorizontal: 24, + paddingTop: 16, + paddingBottom: 4, + }, + title: { + fontSize: 26, + fontWeight: "800", + letterSpacing: -0.5, + }, + subtitle: { + fontSize: 14, + marginTop: 4, + }, + + toggleWrapper: { + paddingHorizontal: 24, + marginTop: 14, + }, + toggleTrack: { + flexDirection: "row", + borderRadius: 10, + padding: 3, + }, + toggleBtn: { + flex: 1, + paddingVertical: 8, + borderRadius: 8, + alignItems: "center", + flexDirection: "row", + justifyContent: "center", + gap: 6, + }, + toggleText: { + fontSize: 14, + fontWeight: "600", + }, + savePill: { + borderRadius: 20, + paddingHorizontal: 6, + paddingVertical: 1, + }, + savePillText: { + fontSize: 10, + fontWeight: "700", + color: "#fff", + }, + + // Card + card: { + borderRadius: 20, + padding: 22, + shadowOffset: { width: 0, height: 6 }, + shadowRadius: 20, + elevation: 6, + }, + badgeRow: { marginBottom: 10 }, + badgePlaceholder: { height: 24, marginBottom: 10 }, + badge: { + alignSelf: "flex-start", + backgroundColor: "rgba(255,255,255,0.25)", + borderRadius: 20, + paddingHorizontal: 10, + paddingVertical: 3, + borderWidth: 1, + borderColor: "rgba(255,255,255,0.35)", + }, + badgeText: { + fontSize: 10, + fontWeight: "700", + color: "#fff", + letterSpacing: 1, + }, + tierLabel: { + fontSize: 11, + fontWeight: "500", + letterSpacing: 0.5, + marginBottom: 8, + }, + planName: { + fontSize: 32, + fontWeight: "800", + letterSpacing: -0.5, + lineHeight: 36, + }, + planNameItalic: { + fontStyle: "italic", + fontWeight: "400", + fontSize: 28, + }, + tagline: { + fontSize: 13, + marginTop: 6, + }, + divider: { + height: 1, + marginVertical: 16, + }, + priceRow: { + flexDirection: "row", + alignItems: "center", + justifyContent: "space-between", + }, + ctaBtn: { + paddingHorizontal: 22, + paddingVertical: 12, + borderRadius: 50, + }, + ctaBtnText: { + fontSize: 15, + fontWeight: "700", + }, + priceBlock: { + flexDirection: "row", + alignItems: "flex-start", + }, + priceDollar: { + fontSize: 14, + marginTop: 4, + fontWeight: "500", + }, + priceAmount: { + fontSize: 36, + fontWeight: "800", + lineHeight: 40, + letterSpacing: -1, + }, + priceCents: { + fontSize: 13, + fontWeight: "600", + lineHeight: 18, + }, + pricePer: { + fontSize: 11, + lineHeight: 14, + }, + featureList: { gap: 10 }, + featureRow: { + flexDirection: "row", + alignItems: "flex-start", + gap: 10, + }, + checkMark: { + fontSize: 13, + fontWeight: "700", + marginTop: 2, + }, + featureText: { + fontSize: 13, + lineHeight: 18, + flex: 1, + }, + + dotsRow: { + flexDirection: "row", + justifyContent: "center", + alignItems: "center", + gap: 6, + marginTop: 4, + marginBottom: 8, + }, + dot: { + height: 6, + borderRadius: 3, + }, + cancelNote: { + fontSize: 12, + textAlign: "center", + paddingBottom: 20, + }, +}); diff --git a/locales/en.json b/locales/en.json index cce1b33..edffb04 100644 --- a/locales/en.json +++ b/locales/en.json @@ -165,6 +165,7 @@ "settings": { "title": "Settings", "personalDetails": "Personal Details", + "subscription": "Subscriptions", "interests": "Interests", "termsAndConditions": "Terms and Conditions", "privacyPolicy": "Privacy & Policy",