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>
This commit is contained in:
parent
56499d5af9
commit
83ab4df537
138 changed files with 19136 additions and 7681 deletions
112
lib/hooks/useAuth.ts
Normal file
112
lib/hooks/useAuth.ts
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* 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),
|
||||
};
|
||||
}
|
||||
*/
|
||||
Loading…
Add table
Add a link
Reference in a new issue