Files
cardclaws/cardclaws-mobile/app/card/[cardId]/view.tsx
T
Omar SobhandClaude Opus 4.8 bc6f158f43
CI / policy (push) Successful in 4s
CI / profile (push) Successful in 12s
CI / mobile (push) Successful in 31s
CI / backend (push) Failing after 1m9s
Mobile: standalone photo demo + full-bleed full-screen cards
- New /demo flow (no login/backend): take/pick a photo → card front;
  swipe → back reveals QR + name/title. Built in-memory on device.
- CardFace renders image backgrounds (local URI or asset key) + borderRadius prop
- CardViewer `fullScreen` mode fills the device window (useWindowDimensions),
  radius 0, status bar hidden; applied to the demo and the real card viewer
- Landing screen offers the demo without signing in
- Added expo-image-picker (camera/photo perms); pinned expo-constants/expo-linking
  to SDK 51 (npm had resolved newer-SDK majors that broke the Gradle build)
- Native android/ is gitignored (regenerated by `expo prebuild`)

Built and deployed to a physical Android device (BUILD SUCCESSFUL).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-04 17:49:52 -05:00

63 lines
2.0 KiB
TypeScript

import { useQuery } from "@tanstack/react-query";
import { Stack, useLocalSearchParams, useRouter } from "expo-router";
import { useState } from "react";
import { ActivityIndicator, Pressable, StyleSheet, Text, View } from "react-native";
import { getCard } from "../../../src/api/cards";
import { CardViewer } from "../../../src/components/card/CardViewer";
import { ShareSheet } from "../../../src/components/share/ShareSheet";
export default function CardViewScreen() {
const { cardId } = useLocalSearchParams<{ cardId: string }>();
const router = useRouter();
const [sharing, setSharing] = useState(false);
const { data, isLoading } = useQuery({
queryKey: ["card", cardId],
queryFn: () => getCard(cardId),
enabled: !!cardId,
});
return (
<View style={{ flex: 1, backgroundColor: "#0a0a0c" }}>
<Stack.Screen
options={{
title: "",
headerTransparent: true,
headerRight: () => (
<View style={styles.actions}>
<Pressable onPress={() => router.push(`/card/${cardId}/analytics`)}>
<Text style={styles.headerBtn}>Stats</Text>
</Pressable>
<Pressable onPress={() => setSharing(true)}>
<Text style={[styles.headerBtn, styles.share]}>Share</Text>
</Pressable>
</View>
),
}}
/>
{isLoading || !data ? (
<View style={styles.center}>
<ActivityIndicator color="#ff3b30" />
</View>
) : (
<>
<CardViewer card={data.definition} fullScreen />
<ShareSheet
cardId={cardId}
handle={data.handle}
visible={sharing}
onClose={() => setSharing(false)}
/>
</>
)}
</View>
);
}
const styles = StyleSheet.create({
center: { flex: 1, alignItems: "center", justifyContent: "center" },
actions: { flexDirection: "row", gap: 16 },
headerBtn: { color: "#f5f5f7", fontWeight: "600", fontSize: 16 },
share: { color: "#ff3b30" },
});