scry/lib/hooks/useAuth.ts
Chris Kruining 83ab4df537
Migrate from .NET MAUI to Expo + Convex
Complete rewrite of Scry using TypeScript stack:

- Expo/React Native with Expo Router (file-based routing)
- Convex backend (serverless functions + real-time database)
- Adaptive camera system (expo-camera in Expo Go, Vision Camera in production)
- React Native Skia + fast-opencv for image processing
- GDPR-compliant auth setup with Zitadel OIDC (pending configuration)

Key features:
- Card recognition pipeline ported to TypeScript
- Perceptual hashing (192-bit color pHash)
- CLAHE preprocessing for lighting normalization
- Local SQLite cache with Convex sync
- Collection management with offline support

Removes all .NET/MAUI code (src/, test/, tools/).

💘 Generated with Crush

Assisted-by: Claude Opus 4.5 via Crush <crush@charm.land>
2026-02-09 16:16:34 +01:00

112 lines
3 KiB
TypeScript

/**
* Authentication hook and utilities.
*
* NOTE: Auth is currently disabled (using ConvexProvider instead of ConvexAuthProvider).
* This hook provides a stub implementation until Zitadel is configured.
*/
import { useState, useCallback } from "react";
/**
* Hook for authentication state and actions.
* Currently returns unauthenticated state - enable ConvexAuthProvider when Zitadel is ready.
*/
export function useAuth() {
const [error, setError] = useState<string | null>(null);
const handleSignIn = useCallback(async () => {
setError("Authentication not configured. Set up Zitadel environment variables.");
}, []);
const handleSignOut = useCallback(async () => {
// No-op when not authenticated
}, []);
return {
isAuthenticated: false,
isLoading: false,
error,
signIn: handleSignIn,
signOut: handleSignOut,
clearError: () => setError(null),
};
}
// Full implementation for when ConvexAuthProvider is enabled:
/*
import { useConvexAuth } from "convex/react";
import { useAuthActions } from "@convex-dev/auth/react";
import { makeRedirectUri } from "expo-auth-session";
import { openAuthSessionAsync } from "expo-web-browser";
import { Platform } from "react-native";
const redirectUri = makeRedirectUri({
scheme: "scry",
path: "auth",
});
export function useAuth() {
const { isAuthenticated, isLoading } = useConvexAuth();
const { signIn, signOut } = useAuthActions();
const [isSigningIn, setIsSigningIn] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleSignIn = useCallback(async () => {
setIsSigningIn(true);
setError(null);
try {
const result = await signIn("zitadel", { redirectTo: redirectUri });
if (Platform.OS === "web") {
return;
}
if (result?.redirect) {
const authResult = await openAuthSessionAsync(
result.redirect.toString(),
redirectUri,
{
showInRecents: true,
preferEphemeralSession: false,
}
);
if (authResult.type === "success") {
const url = new URL(authResult.url);
const code = url.searchParams.get("code");
if (code) {
await signIn("zitadel", { code });
}
} else if (authResult.type === "cancel") {
setError("Sign-in was cancelled");
}
}
} catch (err) {
console.error("Sign-in error:", err);
setError(err instanceof Error ? err.message : "Sign-in failed");
} finally {
setIsSigningIn(false);
}
}, [signIn]);
const handleSignOut = useCallback(async () => {
try {
await signOut();
} catch (err) {
console.error("Sign-out error:", err);
setError(err instanceof Error ? err.message : "Sign-out failed");
}
}, [signOut]);
return {
isAuthenticated,
isLoading: isLoading || isSigningIn,
error,
signIn: handleSignIn,
signOut: handleSignOut,
clearError: () => setError(null),
};
}
*/