diff --git a/ArtisanConnect/api/categories.jsx b/ArtisanConnect/api/categories.jsx index 8ebbebb..9b95b55 100644 --- a/ArtisanConnect/api/categories.jsx +++ b/ArtisanConnect/api/categories.jsx @@ -13,6 +13,6 @@ export async function listCategories() { }); return response.data; } catch (err) { - console.error("Nie udało się pobrać listy kategorii.", err.response.status); + // console.error("Nie udało się pobrać listy kategorii.", err.response.status); } } diff --git a/ArtisanConnect/api/client.jsx b/ArtisanConnect/api/client.jsx index 2faf2fa..4793d4d 100644 --- a/ArtisanConnect/api/client.jsx +++ b/ArtisanConnect/api/client.jsx @@ -7,10 +7,9 @@ export async function getUserById(userId) { const { token } = useAuthStore.getState(); const headers = token ? { Authorization: `Bearer ${token}` } : {}; try { - const response = await axios.get( - `${API_URL}/clients/get/${userId}`, - headers - ); + const response = await axios.get(`${API_URL}/clients/get/${userId}`, { + headers: headers, + }); return response.data; } catch (err) { console.error( diff --git a/ArtisanConnect/app/(tabs)/index.jsx b/ArtisanConnect/app/(tabs)/index.jsx index b9b3099..63d8a26 100644 --- a/ArtisanConnect/app/(tabs)/index.jsx +++ b/ArtisanConnect/app/(tabs)/index.jsx @@ -15,15 +15,15 @@ export default function Home() { const [isReady, setIsReady] = useState(false); const fetchNotices = useNoticesStore((state) => state.fetchNotices); - useEffect(() => { - setIsReady(true); - }, []); + // useEffect(() => { + // setIsReady(true); + // }, []); - useEffect(() => { - if (isReady && !token) { - router.replace("/login"); - } - }, [isReady, token, router]); + // useEffect(() => { + // if (isReady && !token) { + // router.replace("/login"); + // } + // }, [isReady, token, router]); useEffect(() => { if (token) { diff --git a/ArtisanConnect/app/notice/[id].jsx b/ArtisanConnect/app/notice/[id].jsx index 5ad9b2f..9c1a4be 100644 --- a/ArtisanConnect/app/notice/[id].jsx +++ b/ArtisanConnect/app/notice/[id].jsx @@ -5,7 +5,6 @@ import { Heading } from "@/components/ui/heading"; import { Image } from "@/components/ui/image"; import { Text } from "@/components/ui/text"; import { VStack } from "@/components/ui/vstack"; -import { Avatar, AvatarImage, AvatarFallbackText } from "@gluestack-ui/themed"; import { Ionicons } from "@expo/vector-icons"; import { ActivityIndicator, @@ -13,16 +12,14 @@ import { FlatList, View, TextInput, - SafeAreaView, Alert, } from "react-native"; import { useEffect, useState, useRef } from "react"; import { useNoticesStore } from "@/store/noticesStore"; import { useWishlist } from "@/store/wishlistStore"; import { Pressable, ScrollView } from "react-native"; import { getUserById } from "@/api/client"; -import * as ScreenOrientation from "expo-screen-orientation"; -import { useAuthStore } from "@/store/authStore"; -import { sendEmail } from "@/api/email"; + +const { width } = Dimensions.get("window"); export default function NoticeDetails() { const { id } = useLocalSearchParams(); @@ -33,148 +30,49 @@ export default function NoticeDetails() { const [notice, setNotice] = useState(null); const [user, setUser] = useState(null); const [isUserLoading, setIsUserLoading] = useState(true); - const [isLandscape, setIsLandscape] = useState(false); const flatListRef = useRef(null); const [currentIndex, setCurrentIndex] = useState(0); + const [isMessageFormVisible, setIsMessageFormVisible] = useState(false); const [message, setMessage] = useState(""); - const [isSending, setIsSending] = useState(false); + const [Email, setEmail] = useState(""); + const handleSendMessage = () => { + console.log("Wiadomość do:", user?.email); + console.log("Email nadawcy:", Email); + console.log("Treść:", message); - - const handleSendMessage = async () => { - setIsSending(true); - console.log("Rozpoczynanie procesu wysyłania wiadomości..."); - - const { user_id, token } = useAuthStore.getState(); - console.log("Dane z authStore:", { user_id, token }); - - if (!user_id || !token) { - console.error("Brak danych zalogowanego użytkownika."); - Alert.alert("Błąd", "Zaloguj się, aby wysłać wiadomość."); - setIsSending(false); - return; - } - - let currentUserEmail = ""; - try { - console.log(`Pobieranie danych użytkownika dla user_id: ${user_id}`); - const currentUser = await getUserById(user_id); - console.log("Dane zalogowanego użytkownika:", currentUser); - currentUserEmail = currentUser?.email; - if (!currentUserEmail) { - console.error("Nie znaleziono adresu email zalogowanego użytkownika."); - Alert.alert("Błąd", "Nie znaleziono adresu email zalogowanego użytkownika."); - setIsSending(false); - return; - } - console.log(`Pobrano email zalogowanego użytkownika: ${currentUserEmail}`); - } catch (error) { - console.error("Błąd podczas pobierania danych użytkownika:", error); - Alert.alert("Błąd", "Nie udało się pobrać danych użytkownika. Spróbuj ponownie później."); - setIsSending(false); - return; - } - - const emailData = { - to: user?.email || "", - subject: `Zapytanie ${currentUserEmail} o ogłoszenie ${notice.title}`, - body: message, - }; - console.log("Dane emaila do wysyłki:", emailData); - - if (!emailData.to || !emailData.subject || !emailData.body) { - console.error("Walidacja nieudana: brakujące pola w emailData."); - Alert.alert("Błąd", "Wszystkie pola są wymagane!"); - setIsSending(false); - return; - } - - const result = await sendEmail(emailData); - if (result.success) { - console.log("Wiadomość wysłana pomyślnie!", result.result); - setIsMessageFormVisible(false); - setMessage(""); - Alert.alert("Sukces", "Wiadomość została wysłana!"); - } else { - console.error("Błąd podczas wysyłania wiadomości:", result.error); - Alert.alert("Błąd", `Nie udało się wysłać wiadomości: ${result.error}`); - } - setIsSending(false); - console.log("Zakończono proces wysyłania wiadomości."); + setIsMessageFormVisible(false); + setMessage(""); + setEmail(""); }; - const formatDate = (dateString) => { - const date = new Date(dateString); - return date.toLocaleDateString("pl-PL", { - year: "numeric", - month: "2-digit", - day: "2-digit", - }); - }; + const formatDate = (dateString) => { + const date = new Date(dateString); + return date.toLocaleDateString("pl-PL", { + year: "numeric", + month: "2-digit", + day: "2-digit", + }); + }; const { getNoticeById, getAllImagesByNoticeId } = useNoticesStore(); const toggleNoticeInWishlist = useWishlist( - (state) => state.toggleNoticeInWishlist + (state) => state.toggleNoticeInWishlist ); const isInWishlist = useWishlist((state) => - id ? state.wishlistNotices.some((item) => item.noticeId == id) : false + id ? state.wishlistNotices.some((item) => item.noticeId === id) : false ); - const onViewableItemsChanged = useRef(({ viewableItems }) => { if (viewableItems.length > 0) { setCurrentIndex(viewableItems[0].index); } + }).current; const viewabilityConfig = useRef({ itemVisiblePercentThreshold: 70, }).current; - useEffect(() => { - const unlockOrientation = async () => { - try { - await ScreenOrientation.unlockAsync(); - } catch (err) { - console.error("Error unlocking orientation:", err); - } - }; - - const getInitialOrientation = async () => { - try { - const orientation = await ScreenOrientation.getOrientationAsync(); - setIsLandscape( - orientation === ScreenOrientation.Orientation.LANDSCAPE_LEFT || - orientation === ScreenOrientation.Orientation.LANDSCAPE_RIGHT - ); - } catch (err) { - console.error("Error getting initial orientation:", err); - } - }; - - unlockOrientation(); - getInitialOrientation(); - - const subscription = ScreenOrientation.addOrientationChangeListener( - ({ orientationInfo }) => { - const isLandscapeMode = - orientationInfo.orientation === - ScreenOrientation.Orientation.LANDSCAPE_LEFT || - orientationInfo.orientation === - ScreenOrientation.Orientation.LANDSCAPE_RIGHT; - setIsLandscape(isLandscapeMode); - } - ); - - return () => { - ScreenOrientation.removeOrientationChangeListener(subscription); - ScreenOrientation.lockAsync( - ScreenOrientation.OrientationLock.PORTRAIT_UP - ).catch((err) => - console.error("Error locking orientation on unmount:", err) - ); - }; - }, []); - useEffect(() => { const fetchNotice = async () => { setIsLoading(true); @@ -202,15 +100,14 @@ export default function NoticeDetails() { if (notice) { try { const fetchedImages = await getAllImagesByNoticeId(notice.noticeId); - console.log("Fetched images:", fetchedImages); setImages( - fetchedImages && fetchedImages.length > 0 - ? fetchedImages - : ["https://http.cat/404.jpg"] + fetchedImages && fetchedImages.length > 0 + ? fetchedImages + : { uri: "https://http.cat/404.jpg" } ); } catch (err) { console.error("Error while loading images:", err); - setImages(["https://http.cat/404.jpg"]); + setImage({ uri: "https://http.cat/404.jpg" }); } finally { setIsImageLoading(false); } @@ -220,10 +117,22 @@ export default function NoticeDetails() { if (notice) { fetchImage(); } + }, [notice]); - if (!notice) { - return Nie znaleziono ogłoszenia; - } + useEffect(() => { + const fetchUser = async () => { + if (notice && notice.clientId) { + setIsUserLoading(true); + try { + const userData = await getUserById(notice.clientId); + setUser(userData); + } catch (err) { + console.error("Nie udało się pobrać danych użytkownika:", err); + } finally { + setIsUserLoading(false); + } + } + }; fetchUser(); }, [notice]); @@ -233,209 +142,197 @@ export default function NoticeDetails() { } if (error) { - return Błąd, spróbuj ponownie później: {error.message}; + return Błąd, spróbuj ponownie póżniej: {error.message}; } if (!notice) { return Nie znaleziono ogłoszenia; } - const renderImageSection = () => { - if (isImageLoading) { - return ( - - - - ); - } - - return ( - + return ( + + + {isImageLoading ? ( + + + + ) : ( + ( - - {`Zdjęcie console.error("Image load error:", e.nativeEvent.error)} - /> - - )} - keyExtractor={(item, index) => index.toString()} + ref={flatListRef} + data={images} + horizontal + snapToInterval={width} + snapToAlignment="start" + decelerationRate="fast" + showsHorizontalScrollIndicator={false} + pagingEnabled + onViewableItemsChanged={onViewableItemsChanged} + viewabilityConfig={viewabilityConfig} + renderItem={({ item, index }) => ( + + {`Zdjęcie + + )} + keyExtractor={(item, index) => index.toString()} /> + {images.length > 1 && ( - - {images.map((_, index) => ( - - ))} - + + {images.map((_, index) => ( + + ))} + )} - ); - }; + )} - return ( - - - + + + {formatDate(notice.publishDate)} + + + {notice.title} + + + + + Cena: + {notice.price} zł + + + { + toggleNoticeInWishlist(id); }} - /> - - {renderImageSection()} - - - {formatDate(notice.publishDate)} - - - {notice.title} - - - - Cena: - {notice.price} zł - - { - toggleNoticeInWishlist(id); - }} - > - + + + + + + Kategoria:{" "} + {notice.category} + + + + Opis ogloszenia + + {notice.description} + + + + + Uzytkownik: + {isUserLoading ? ( + + ) : user ? ( + <> + + Zdjęcie profilowe - - - - - Kategoria:{" "} - {notice.category} - - - - Opis ogłoszenia - {notice.description} - - - Użytkownik: - {isUserLoading ? ( - - ) : user ? ( - <> - - - - - {user.firstName?.[0]} - {user.lastName?.[0]} - - - - - - {user.firstName} {user.lastName} - - - Email: {user.email} - - setIsMessageFormVisible(true)} - className="mt-3 bg-blue-500 py-2 px-4 rounded-md" - > - - Wyślij wiadomość - - - - - Zobacz więcej ogłoszeń od {user.firstName} - - - - - ) : ( - Błąd podczas ładowania danych użytkownika - )} - - - - {isMessageFormVisible && ( - - - - Wyślij wiadomość do {user?.firstName} + + + + + {user.firstName} {user.lastName} - Do: - - {user?.email || "Brak adresu e-mail"} + + Email: {user.email} - Temat: - - Zapytanie o ogłoszenie '{notice.title || "Brak nazwy ogłoszenia"}' - - Treść: - - - setIsMessageFormVisible(false)} - className="bg-gray-300 py-2 px-4 rounded-md" - > - Anuluj - - - {isSending ? ( - - ) : ( - Wyślij - )} - - - - - )} - - + setIsMessageFormVisible(true)} + className="mt-3 bg-primary-500 py-2 px-4 rounded-md" + > + + Wyślij wiadomość + + + + + Zobacz więcej ogłoszeń od {user.firstName} + + + + + ) : ( + Błąd podczas ładowania danych użytkownika + )} + + + + {isMessageFormVisible && ( + + + + Wyślij wiadomość do {user?.firstName} + + + Do: + + {user?.email || "Brak adresu e-mail"} + + Twój e-mail: + + + + + + setIsMessageFormVisible(false)} + className="bg-gray-300 py-2 px-4 rounded-md" + > + Anuluj + + + + Wyślij + + + + + )} + ); } diff --git a/ArtisanConnect/components/CategorySection.jsx b/ArtisanConnect/components/CategorySection.jsx index cb82cd1..7d6fa60 100644 --- a/ArtisanConnect/components/CategorySection.jsx +++ b/ArtisanConnect/components/CategorySection.jsx @@ -1,6 +1,5 @@ import { View, FlatList } from "react-native"; import { useEffect, useState } from "react"; -import { useAuthStore } from "@/store/authStore"; import { Heading } from "@/components/ui/heading"; import { Text } from "@/components/ui/text"; import { Link } from "expo-router"; @@ -17,7 +16,6 @@ export function CategorySection({ notices, title }) { setCategoryMap(data); } }; - fetchCategories(); }, []); diff --git a/ArtisanConnect/store/authStore.jsx b/ArtisanConnect/store/authStore.jsx index fd9a468..5ad2d40 100644 --- a/ArtisanConnect/store/authStore.jsx +++ b/ArtisanConnect/store/authStore.jsx @@ -11,22 +11,23 @@ let interceptorInitialized = false; export const useAuthStore = create( persist( (set, get) => { - // if (!interceptorInitialized.current) { - // axios.interceptors.response.use( - // (response) => response, - // (error) => { - // if ( - // (error.response && error.response.status === 401) || - // error.response.status === 403 - // ) { - // set({ user_id: null, token: null, isLoading: false }); - // delete axios.defaults.headers.common["Authorization"]; - // } - // return Promise.reject(error); - // } - // ); - // interceptorInitialized = true; - // } + if (!interceptorInitialized.current) { + axios.interceptors.response.use( + (response) => response, + (error) => { + if ( + (error.response && error.response.status === 401) || + error.response.status === 403 + ) { + set({ user_id: null, token: null, isLoading: false }); + delete axios.defaults.headers.common["Authorization"]; + router.replace("/login"); + } + return Promise.reject(error); + } + ); + interceptorInitialized = true; + } return { user_id: null, token: null,