97 lines
2.4 KiB
TypeScript
97 lines
2.4 KiB
TypeScript
import React, {
|
|
createContext,
|
|
useCallback,
|
|
useContext,
|
|
useEffect,
|
|
useMemo,
|
|
useState,
|
|
type ReactNode,
|
|
} from "react";
|
|
import { useAuth, useUser } from "@clerk/clerk-expo";
|
|
import {
|
|
getCurrentMembershipFeaturesFromServer,
|
|
type MembershipFeatures,
|
|
type MembershipType,
|
|
} from "../api/membership";
|
|
import log from "../utils/logger";
|
|
|
|
const BASIC_FEATURES: MembershipFeatures = {
|
|
recommendationsPerMonth: 1,
|
|
hydrationTracking: false,
|
|
nutritionTracking: false,
|
|
advancedStatistics: false,
|
|
};
|
|
|
|
interface MembershipContextValue {
|
|
membershipType: MembershipType;
|
|
features: MembershipFeatures;
|
|
loading: boolean;
|
|
refreshMembership: () => Promise<void>;
|
|
}
|
|
|
|
const MembershipContext = createContext<MembershipContextValue | undefined>(
|
|
undefined,
|
|
);
|
|
|
|
export function MembershipProvider({ children }: { children: ReactNode }) {
|
|
const { user } = useUser();
|
|
const { getToken, isSignedIn } = useAuth();
|
|
const [membershipType, setMembershipType] = useState<MembershipType>("basic");
|
|
const [features, setFeatures] = useState<MembershipFeatures>(BASIC_FEATURES);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const loadMembership = useCallback(async () => {
|
|
if (!isSignedIn || !user?.id) {
|
|
setMembershipType("basic");
|
|
setFeatures(BASIC_FEATURES);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setLoading(true);
|
|
const token = await getToken();
|
|
const result = await getCurrentMembershipFeaturesFromServer(token);
|
|
setMembershipType(result.membershipType);
|
|
setFeatures(result.features);
|
|
} catch (error) {
|
|
log.error("Failed to load membership", error, { userId: user.id });
|
|
setMembershipType("basic");
|
|
setFeatures(BASIC_FEATURES);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [isSignedIn, user?.id]);
|
|
|
|
useEffect(() => {
|
|
loadMembership();
|
|
}, [loadMembership]);
|
|
|
|
const value = useMemo(
|
|
() => ({
|
|
membershipType,
|
|
features,
|
|
loading,
|
|
refreshMembership: loadMembership,
|
|
}),
|
|
[membershipType, features, loading, loadMembership],
|
|
);
|
|
|
|
return (
|
|
<MembershipContext.Provider value={value}>
|
|
{children}
|
|
</MembershipContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useMembershipContext(): MembershipContextValue {
|
|
const context = useContext(MembershipContext);
|
|
if (!context) {
|
|
throw new Error(
|
|
"useMembershipContext must be used within MembershipProvider",
|
|
);
|
|
}
|
|
|
|
return context;
|
|
}
|