Files
Dennis Hundertmark b24544f115 Initial commit
Generated by create-expo-app 3.2.0.
2025-05-20 15:23:02 +02:00

168 lines
3.8 KiB
TypeScript

import { ProductDetailsShimmer } from "@/components/ProductDetailsShimmer";
import { fetchProduct } from "@/utils/api";
import { COLORS } from "@/utils/colors";
import { useQuery } from "@tanstack/react-query";
import { Image } from "expo-image";
import { Stack, useLocalSearchParams } from "expo-router";
import React from "react";
import useCartStore from "@/store/cartStore";
import { Ionicons } from "@expo/vector-icons";
import {
Platform,
ScrollView,
Share,
StyleSheet,
Text,
TouchableOpacity,
View,
} from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
const Page = () => {
const { id } = useLocalSearchParams();
const { bottom } = useSafeAreaInsets();
const { addProduct } = useCartStore();
const { data: product, isLoading } = useQuery({
queryKey: ["product", id],
queryFn: () => fetchProduct(Number(id)),
});
const onShare = async () => {
const url = `mnkyshop://product/${product?.id}`;
if (Platform.OS === "ios") {
await Share.share({
url,
message: `Check out this product on Galaxies Shop: ${url}`,
});
} else {
await Share.share({
message: `Check out this product on Galaxies Shop: ${url}`,
});
}
};
if (isLoading) {
return <ProductDetailsShimmer />;
}
if (!product) {
return <Text>Product not found</Text>;
}
const handleAddToCart = () => {
addProduct(product);
};
return (
<View style={styles.container}>
<Stack.Screen
options={{
title: product?.title,
headerRight: () => (
<TouchableOpacity onPress={onShare}>
<Ionicons name="share-outline" size={24} color={COLORS.primary} />
</TouchableOpacity>
),
}}
/>
<ScrollView>
<Image
source={{ uri: product.image }}
style={styles.image}
contentFit="contain"
/>
<View style={styles.content}>
<Text style={styles.title}>{product.title}</Text>
<Text style={styles.price}>${product.price}</Text>
<Text style={styles.category}>{product.category}</Text>
<Text style={styles.description}>{product.description}</Text>
<View style={styles.ratingContainer}>
<Text style={styles.rating}> {product.rating.rate}</Text>
<Text style={styles.ratingCount}>
({product.rating.count} reviews)
</Text>
</View>
</View>
</ScrollView>
<TouchableOpacity
style={[
styles.addToCartButton,
{ paddingBottom: Platform.OS === "ios" ? bottom : 20 },
]}
onPress={handleAddToCart}
>
<Ionicons name="cart" size={20} color="white" />
<Text style={styles.addToCartText}>Add to Cart</Text>
</TouchableOpacity>
</View>
);
};
export default Page;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
},
image: {
width: "100%",
height: 300,
backgroundColor: "#f9f9f9",
},
content: {
padding: 16,
gap: 12,
},
title: {
fontSize: 24,
fontWeight: "600",
},
price: {
fontSize: 20,
fontWeight: "700",
color: COLORS.primary,
},
category: {
fontSize: 16,
color: "#666",
textTransform: "capitalize",
},
description: {
fontSize: 16,
lineHeight: 24,
color: "#333",
},
ratingContainer: {
flexDirection: "row",
alignItems: "center",
gap: 8,
},
rating: {
fontSize: 16,
fontWeight: "600",
color: "#FFB800",
},
ratingCount: {
fontSize: 14,
color: "#666",
},
addToCartButton: {
backgroundColor: COLORS.primary,
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
gap: 8,
padding: 16,
},
addToCartText: {
color: "white",
fontWeight: "600",
fontSize: 16,
},
});