moved files to monorepo and updated controllers to start with /api
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
View, Text, ScrollView, TouchableOpacity,
|
||||
ActivityIndicator, useColorScheme,
|
||||
} from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { Subject, subjectsApi } from "../services/api";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
|
||||
export default function ManageSubscriptions({ onClose }: { onClose: () => void }) {
|
||||
const dark = useColorScheme() === "dark";
|
||||
const { user, isSubscribed, subscribe, unsubscribe } = useAuth();
|
||||
const accent = dark ? "#E07B45" : "#C4622D";
|
||||
|
||||
const [subjects, setSubjects] = useState<Subject[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
const [toggling, setToggling] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
subjectsApi.getAll(user?.token)
|
||||
.then(setSubjects)
|
||||
.catch(() => setError("Couldn't load subjects."))
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
const toggle = async (subject: Subject) => {
|
||||
setToggling(subject.id);
|
||||
try {
|
||||
if (isSubscribed(subject.id)) await unsubscribe(subject.id);
|
||||
else await subscribe(subject.id);
|
||||
} finally {
|
||||
setToggling(null);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView className={`flex-1 ${dark ? "bg-obsidian-200" : "bg-parchment-50"}`}>
|
||||
{/* Header */}
|
||||
<View className={`flex-row items-center px-4 py-4 border-b ${
|
||||
dark ? "border-border-dark" : "border-border-light"
|
||||
}`}>
|
||||
<Text className={`flex-1 text-xl font-display font-bold ${dark ? "text-ink-dark" : "text-ink-light"}`}>
|
||||
Manage Subscriptions
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={onClose}
|
||||
className={`w-8 h-8 rounded-full items-center justify-center ${dark ? "bg-obsidian-50" : "bg-parchment-200"}`}
|
||||
>
|
||||
<Ionicons name="close" size={18} color={dark ? "#706D67" : "#8A8278"} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Body */}
|
||||
{loading ? (
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<ActivityIndicator color={accent} />
|
||||
</View>
|
||||
|
||||
) : error ? (
|
||||
<View className="flex-1 items-center justify-center px-8">
|
||||
<Text className="text-3xl mb-3">⚠️</Text>
|
||||
<Text className={`text-sm font-sans text-center ${dark ? "text-muted-dark" : "text-muted-light"}`}>
|
||||
{error}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
) : (
|
||||
<ScrollView
|
||||
contentContainerStyle={{ padding: 16, paddingBottom: 40 }}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<View className={`rounded-2xl overflow-hidden border ${
|
||||
dark ? "bg-obsidian-100 border-border-dark" : "bg-surface-light border-border-light"
|
||||
}`}>
|
||||
{subjects.map((subject, index) => {
|
||||
const subscribed = isSubscribed(subject.id);
|
||||
const busy = toggling === subject.id;
|
||||
const isLast = index === subjects.length - 1;
|
||||
|
||||
return (
|
||||
<View
|
||||
key={subject.id}
|
||||
className={`flex-row items-center px-4 py-3.5 ${
|
||||
!isLast ? `border-b ${dark ? "border-border-dark" : "border-border-light"}` : ""
|
||||
}`}
|
||||
>
|
||||
{/* Subscribed indicator dot */}
|
||||
<View
|
||||
className="w-2 h-2 rounded-full mr-3"
|
||||
style={{
|
||||
backgroundColor: subscribed ? accent : "transparent",
|
||||
borderWidth: subscribed ? 0 : 1.5,
|
||||
borderColor: dark ? "#706D67" : "#8A8278",
|
||||
}}
|
||||
/>
|
||||
|
||||
<Text className={`flex-1 text-sm font-sans ${dark ? "text-ink-dark" : "text-ink-light"}`}>
|
||||
{subject.name}
|
||||
</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={() => toggle(subject)}
|
||||
disabled={!!toggling}
|
||||
className="px-3 py-1.5 rounded-xl"
|
||||
style={{
|
||||
backgroundColor: subscribed
|
||||
? dark ? "#2C2A27" : "#F0EDE8"
|
||||
: accent + "20",
|
||||
}}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
{busy ? (
|
||||
<ActivityIndicator size="small" color={accent} style={{ width: 40 }} />
|
||||
) : (
|
||||
<Text className="text-xs font-sans font-semibold" style={{ color: accent }}>
|
||||
{subscribed ? "Unsubscribe" : "Subscribe"}
|
||||
</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</ScrollView>
|
||||
)}
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user