From eb1ebc3464e26c2e9556f935e7e4761bd23a8075 Mon Sep 17 00:00:00 2001 From: Kuba Date: Sun, 25 May 2025 17:41:07 +0200 Subject: [PATCH 1/9] V1 --- ArtisanConnect/api/client.jsx | 13 +++++ ArtisanConnect/app/notice/[id].jsx | 77 ++++++++++++++++++++++++++++-- 2 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 ArtisanConnect/api/client.jsx diff --git a/ArtisanConnect/api/client.jsx b/ArtisanConnect/api/client.jsx new file mode 100644 index 0000000..6f0489c --- /dev/null +++ b/ArtisanConnect/api/client.jsx @@ -0,0 +1,13 @@ +import axios from "axios"; + +const API_URL = "https://testowe.zikor.pl/api/v1"; + +export async function getUserById(userId) { + try { + const response = await axios.get(`${API_URL}/clients/get/${userId}`); + return response.data; + } catch (err) { + console.error(`Nie udało się pobrać danych użytkownika o ID ${userId}.`, err.response.status); + throw err; + } +} diff --git a/ArtisanConnect/app/notice/[id].jsx b/ArtisanConnect/app/notice/[id].jsx index 5847f79..9da0bcd 100644 --- a/ArtisanConnect/app/notice/[id].jsx +++ b/ArtisanConnect/app/notice/[id].jsx @@ -11,6 +11,9 @@ import {useEffect, useState} from "react"; import {useNoticesStore} from "@/store/noticesStore"; import {useWishlist} from "@/store/wishlistStore"; import {Pressable} from "react-native"; +import {getUserById} from "@/api/client"; + + export default function NoticeDetails() { const {id} = useLocalSearchParams(); @@ -19,6 +22,9 @@ export default function NoticeDetails() { const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [notice, setNotice] = useState(null); + const [user, setUser] = useState(null); + const [isUserLoading, setIsUserLoading] = useState(true); + const {getNoticeById, getAllImagesByNoticeId} = useNoticesStore(); const addNoticeToWishlist = useWishlist((state) => state.addNoticeToWishlist); @@ -69,6 +75,25 @@ export default function NoticeDetails() { } }, [notice]); + 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]); + + if (isLoading) { return ; } @@ -105,12 +130,17 @@ export default function NoticeDetails() { + {notice.publishDate} + + {notice.title} - - - {notice.price}zł + + + + {notice.price} zł + { if (isInWishlist) { @@ -127,6 +157,47 @@ export default function NoticeDetails() { /> + + + Kategoria: {notice.category} + + + + + Opis ogloszenia + + + {notice.description} + + + + + + Uzytkownik: + + {isUserLoading ? ( + + ) : user ? ( + + + {user.firstName} {user.lastName} + + + Email: {user.email} + + + ) : ( + Błąd podczas ładowania danych użytkownika + )} + + + + + + {notice.clientId} + + + ); From 06218dcdd40c0abc9a3a4ad4e7fb7976a3f4dace Mon Sep 17 00:00:00 2001 From: Kuba Date: Sun, 25 May 2025 20:38:35 +0200 Subject: [PATCH 2/9] Added Image Slider --- ArtisanConnect/app/notice/[id].jsx | 67 ++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/ArtisanConnect/app/notice/[id].jsx b/ArtisanConnect/app/notice/[id].jsx index 9da0bcd..e4bed13 100644 --- a/ArtisanConnect/app/notice/[id].jsx +++ b/ArtisanConnect/app/notice/[id].jsx @@ -6,24 +6,27 @@ import {Image} from "@/components/ui/image"; import {Text} from "@/components/ui/text"; import {VStack} from "@/components/ui/vstack"; import {Ionicons} from "@expo/vector-icons"; -import {ActivityIndicator} from "react-native"; -import {useEffect, useState} from "react"; +import {ActivityIndicator, Dimensions, FlatList, View} from "react-native"; +import {useEffect, useState, useRef} from "react"; import {useNoticesStore} from "@/store/noticesStore"; import {useWishlist} from "@/store/wishlistStore"; import {Pressable} from "react-native"; import {getUserById} from "@/api/client"; +const {width} = Dimensions.get("window"); export default function NoticeDetails() { const {id} = useLocalSearchParams(); - const [image, setImage] = useState(null); + const [images, setImages] = useState([]); const [isImageLoading, setIsImageLoading] = useState(true); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [notice, setNotice] = useState(null); const [user, setUser] = useState(null); const [isUserLoading, setIsUserLoading] = useState(true); + const flatListRef = useRef(null); + const [currentIndex, setCurrentIndex] = useState(0); const {getNoticeById, getAllImagesByNoticeId} = useNoticesStore(); @@ -32,6 +35,15 @@ export default function NoticeDetails() { const isInWishlist = useWishlist((state) => notice ? state.wishlistNotices.some((item) => item.noticeId === notice.noticeId) : false ); + const onViewableItemsChanged = useRef(({ viewableItems }) => { + if (viewableItems.length > 0) { + setCurrentIndex(viewableItems[0].index); + } + }).current; + + const viewabilityConfig = useRef({ + itemVisiblePercentThreshold: 70, + }).current; useEffect(() => { const fetchNotice = async () => { @@ -59,8 +71,9 @@ export default function NoticeDetails() { setIsImageLoading(true); if (notice) { try { - const images = await getAllImagesByNoticeId(notice.noticeId); - setImage(images && images.length > 0 ? images[0] : "https://http.cat/404.jpg"); + const fetchedImages = await getAllImagesByNoticeId(notice.noticeId); + setImages(fetchedImages && fetchedImages.length > 0 ? fetchedImages : ["https://http.cat/404.jpg"]); + } catch (err) { console.error("Error while loading images:", err); setImage("https://http.cat/404.jpg"); @@ -118,16 +131,44 @@ export default function NoticeDetails() { ) : ( - image + + ( + + {`Zdjęcie + + )} + keyExtractor={(item, index) => index.toString()} + /> + + {images.length > 1 && ( + + {images.map((_, index) => ( + + ))} + + )} + )} + {notice.publishDate} From 925dde0bb0c26ea4a13d7b2f737d69687f718feb Mon Sep 17 00:00:00 2001 From: Kuba Date: Tue, 27 May 2025 20:55:31 +0200 Subject: [PATCH 3/9] Added scrollview and send message button to notice --- ArtisanConnect/app/notice/[id].jsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ArtisanConnect/app/notice/[id].jsx b/ArtisanConnect/app/notice/[id].jsx index e4bed13..20f1e37 100644 --- a/ArtisanConnect/app/notice/[id].jsx +++ b/ArtisanConnect/app/notice/[id].jsx @@ -10,7 +10,7 @@ import {ActivityIndicator, Dimensions, FlatList, View} from "react-native"; import {useEffect, useState, useRef} from "react"; import {useNoticesStore} from "@/store/noticesStore"; import {useWishlist} from "@/store/wishlistStore"; -import {Pressable} from "react-native"; +import {Pressable, ScrollView} from "react-native"; import {getUserById} from "@/api/client"; const {width} = Dimensions.get("window"); @@ -131,7 +131,7 @@ export default function NoticeDetails() { ) : ( - + )} - + {notice.publishDate} @@ -226,6 +228,12 @@ export default function NoticeDetails() { Email: {user.email} + setIsMessageFormVisible(true)} + className="mt-3 bg-primary-500 py-2 px-4 rounded-md" + > + Wyślij wiadomość + ) : ( Błąd podczas ładowania danych użytkownika @@ -238,8 +246,8 @@ export default function NoticeDetails() { {notice.clientId} - + ); } \ No newline at end of file From 95a632741a58e3cf8048f41489d3af74bc3a1481 Mon Sep 17 00:00:00 2001 From: Kuba Date: Tue, 27 May 2025 22:28:28 +0200 Subject: [PATCH 4/9] Added send message form --- ArtisanConnect/app/notice/[id].jsx | 71 +++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/ArtisanConnect/app/notice/[id].jsx b/ArtisanConnect/app/notice/[id].jsx index 20f1e37..7d8dac6 100644 --- a/ArtisanConnect/app/notice/[id].jsx +++ b/ArtisanConnect/app/notice/[id].jsx @@ -6,7 +6,7 @@ import {Image} from "@/components/ui/image"; import {Text} from "@/components/ui/text"; import {VStack} from "@/components/ui/vstack"; import {Ionicons} from "@expo/vector-icons"; -import {ActivityIndicator, Dimensions, FlatList, View} from "react-native"; +import {ActivityIndicator, Dimensions, FlatList, View, TextInput} from "react-native"; import {useEffect, useState, useRef} from "react"; import {useNoticesStore} from "@/store/noticesStore"; import {useWishlist} from "@/store/wishlistStore"; @@ -29,6 +29,19 @@ export default function NoticeDetails() { const [currentIndex, setCurrentIndex] = useState(0); + const [isMessageFormVisible, setIsMessageFormVisible] = useState(false); + const [message, setMessage] = useState(''); + const [Email, setEmail] = useState(''); + const handleSendMessage = () => { + console.log('Wiadomość do:', user?.email); + console.log('Email nadawcy:', Email); + console.log('Treść:', message); + + setIsMessageFormVisible(false); + setMessage(''); + setEmail(''); + }; + const {getNoticeById, getAllImagesByNoticeId} = useNoticesStore(); const addNoticeToWishlist = useWishlist((state) => state.addNoticeToWishlist); const removeNoticeFromWishlist = useWishlist((state) => state.removeNoticeFromWishlist); @@ -221,7 +234,16 @@ export default function NoticeDetails() { {isUserLoading ? ( ) : user ? ( - + <> + + Zdjęcie profilowe + + + {user.firstName} {user.lastName} @@ -235,6 +257,7 @@ export default function NoticeDetails() { Wyślij wiadomość + ) : ( Błąd podczas ładowania danych użytkownika )} @@ -248,6 +271,50 @@ export default function NoticeDetails() { + {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 + + + + + )} + ); } \ No newline at end of file From 774b2ef192a8beb4ef5e67c251a587e75c6c66f4 Mon Sep 17 00:00:00 2001 From: Kuba Date: Tue, 27 May 2025 23:51:31 +0200 Subject: [PATCH 5/9] improved display of the time of adding notice --- ArtisanConnect/app/notice/[id].jsx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ArtisanConnect/app/notice/[id].jsx b/ArtisanConnect/app/notice/[id].jsx index 7d8dac6..2547aac 100644 --- a/ArtisanConnect/app/notice/[id].jsx +++ b/ArtisanConnect/app/notice/[id].jsx @@ -42,6 +42,15 @@ export default function NoticeDetails() { setEmail(''); }; + 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 addNoticeToWishlist = useWishlist((state) => state.addNoticeToWishlist); const removeNoticeFromWishlist = useWishlist((state) => state.removeNoticeFromWishlist); @@ -58,6 +67,7 @@ export default function NoticeDetails() { itemVisiblePercentThreshold: 70, }).current; + useEffect(() => { const fetchNotice = async () => { setIsLoading(true); @@ -186,7 +196,7 @@ export default function NoticeDetails() { > - {notice.publishDate} + {formatDate(notice.publishDate)} {notice.title} @@ -194,6 +204,7 @@ export default function NoticeDetails() { + Cena: {notice.price} zł @@ -264,11 +275,6 @@ export default function NoticeDetails() { - - - {notice.clientId} - - {isMessageFormVisible && ( From d12ae04f8ac2de20da6b8e51f29a919e7ad30645 Mon Sep 17 00:00:00 2001 From: Kuba Date: Mon, 2 Jun 2025 23:56:56 +0200 Subject: [PATCH 6/9] added the ability to see the notices of a particular user(transition from the notice) --- ArtisanConnect/app/notice/[id].jsx | 9 +++- ArtisanConnect/app/user/[userId].jsx | 69 ++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 ArtisanConnect/app/user/[userId].jsx diff --git a/ArtisanConnect/app/notice/[id].jsx b/ArtisanConnect/app/notice/[id].jsx index 2547aac..a0fad91 100644 --- a/ArtisanConnect/app/notice/[id].jsx +++ b/ArtisanConnect/app/notice/[id].jsx @@ -1,4 +1,4 @@ -import {Stack, useLocalSearchParams} from "expo-router"; +import {Link, Stack, useLocalSearchParams} from "expo-router"; import {Box} from "@/components/ui/box"; import {Card} from "@/components/ui/card"; import {Heading} from "@/components/ui/heading"; @@ -6,7 +6,7 @@ import {Image} from "@/components/ui/image"; import {Text} from "@/components/ui/text"; import {VStack} from "@/components/ui/vstack"; import {Ionicons} from "@expo/vector-icons"; -import {ActivityIndicator, Dimensions, FlatList, View, TextInput} from "react-native"; +import {ActivityIndicator, Dimensions, FlatList, View, TextInput, TouchableOpacity} from "react-native"; import {useEffect, useState, useRef} from "react"; import {useNoticesStore} from "@/store/noticesStore"; import {useWishlist} from "@/store/wishlistStore"; @@ -267,6 +267,11 @@ export default function NoticeDetails() { > Wyślij wiadomość + + + Zobacz więcej ogłoszeń od {user.firstName} + + ) : ( diff --git a/ArtisanConnect/app/user/[userId].jsx b/ArtisanConnect/app/user/[userId].jsx new file mode 100644 index 0000000..0f85231 --- /dev/null +++ b/ArtisanConnect/app/user/[userId].jsx @@ -0,0 +1,69 @@ +import { useLocalSearchParams } from "expo-router"; +import { useState, useEffect } from "react"; +import { FlatList, ActivityIndicator, Text } from "react-native"; +import { Box } from "@/components/ui/box"; +import { Image } from "@/components/ui/image"; +import { VStack } from "@/components/ui/vstack"; +import { Heading } from "@/components/ui/heading"; +import { getUserById } from "@/api/client"; +import { useNoticesStore } from "@/store/noticesStore"; +import { NoticeCard } from "@/components/NoticeCard"; + +export default function UserProfile() { + const { userId } = useLocalSearchParams(); + const [user, setUser] = useState(null); + const [isUserLoading, setIsUserLoading] = useState(true); + const { notices } = useNoticesStore(); + + useEffect(() => { + const fetchUser = async () => { + setIsUserLoading(true); + try { + const userData = await getUserById(Number(userId)); + setUser(userData); + } catch (err) { + console.error("Błąd podczas pobierania danych użytkownika:", err); + setUser(null); + } finally { + setIsUserLoading(false); + } + }; + fetchUser(); + }, [userId]); + + if (isUserLoading) { + return ; + } + + if (!user) { + return Nie znaleziono użytkownika; + } + + const userNotices = notices.filter(notice => notice.clientId === Number(userId)); + + return ( + + + Zdjęcie profilowe + + {user.firstName} {user.lastName} + + + {userNotices.length > 0 ? ( + } + keyExtractor={(item) => item.noticeId.toString()} + /> + ) : ( + Ten użytkownik nie ma żadnych ogłoszeń. + )} + + ); +} \ No newline at end of file From 1c57984a36946cb98c5ee43357477d33167764c8 Mon Sep 17 00:00:00 2001 From: Kuba Date: Mon, 2 Jun 2025 23:59:05 +0200 Subject: [PATCH 7/9] Improved looking --- ArtisanConnect/app/notice/[id].jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ArtisanConnect/app/notice/[id].jsx b/ArtisanConnect/app/notice/[id].jsx index a0fad91..f95f3c6 100644 --- a/ArtisanConnect/app/notice/[id].jsx +++ b/ArtisanConnect/app/notice/[id].jsx @@ -6,7 +6,7 @@ import {Image} from "@/components/ui/image"; import {Text} from "@/components/ui/text"; import {VStack} from "@/components/ui/vstack"; import {Ionicons} from "@expo/vector-icons"; -import {ActivityIndicator, Dimensions, FlatList, View, TextInput, TouchableOpacity} from "react-native"; +import {ActivityIndicator, Dimensions, FlatList, View, TextInput} from "react-native"; import {useEffect, useState, useRef} from "react"; import {useNoticesStore} from "@/store/noticesStore"; import {useWishlist} from "@/store/wishlistStore"; @@ -268,7 +268,7 @@ export default function NoticeDetails() { Wyślij wiadomość - + Zobacz więcej ogłoszeń od {user.firstName} From 8722488a45df11f0f200796b6b2fde46aa77914a Mon Sep 17 00:00:00 2001 From: Kuba Date: Tue, 3 Jun 2025 00:19:12 +0200 Subject: [PATCH 8/9] Added content to account.jsx and userNotices.jsx --- .../app/(tabs)/dashboard/account.jsx | 74 +++++++++++++++++- .../app/(tabs)/dashboard/userNotices.jsx | 77 ++++++++++++++++++- 2 files changed, 144 insertions(+), 7 deletions(-) diff --git a/ArtisanConnect/app/(tabs)/dashboard/account.jsx b/ArtisanConnect/app/(tabs)/dashboard/account.jsx index 7d3093d..25d74a6 100644 --- a/ArtisanConnect/app/(tabs)/dashboard/account.jsx +++ b/ArtisanConnect/app/(tabs)/dashboard/account.jsx @@ -1,4 +1,70 @@ -import { Text } from "@/components/ui/text"; -export default function User() { - return Użytkownik; -} +import { Link } from "expo-router"; +import {Button} from "react-native"; +import {Box} from "@/components/ui/box"; +import {Text} from "@/components/ui/text"; +import {VStack} from "@/components/ui/vstack"; +import {Image} from "@/components/ui/image"; +import {ActivityIndicator, } from "react-native"; +import {useEffect, useState} from "react"; +import {getUserById} from "@/api/client"; + +export default function Account() { + const [user, setUser] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const currentUserId = 1; // Tymczasowo, do czasu zaimplementowania logowania bo nie moge pobrac usera + + useEffect(() => { + const fetchUser = async () => { + setIsLoading(true); + try { + const userData = await getUserById(currentUserId); + setUser(userData); + } catch (err) { + console.error("Błąd podczas pobierania danych użytkownika:", err); + } finally { + setIsLoading(false); + } + }; + fetchUser(); + }, []); + + if (isLoading) { + return ; + } + + if (!user) { + return Nie udało się pobrać danych użytkownika.; + } + + return ( + + + Zdjęcie profilowe + + {user.firstName} {user.lastName} + + + + + + Moje ogłoszenia + + + Moje płatności + + + + ); +} \ No newline at end of file diff --git a/ArtisanConnect/app/(tabs)/dashboard/userNotices.jsx b/ArtisanConnect/app/(tabs)/dashboard/userNotices.jsx index 9f5ef2f..7fe0f2b 100644 --- a/ArtisanConnect/app/(tabs)/dashboard/userNotices.jsx +++ b/ArtisanConnect/app/(tabs)/dashboard/userNotices.jsx @@ -1,4 +1,75 @@ -import { Text } from "@/components/ui/text"; +import { useNoticesStore } from "@/store/noticesStore"; +import { NoticeCard } from "@/components/NoticeCard"; +import {Button} from "react-native"; +import {Box} from "@/components/ui/box"; +import {Text} from "@/components/ui/text"; +import {VStack} from "@/components/ui/vstack"; +import {ActivityIndicator, FlatList } from "react-native"; +import {useEffect, useState} from "react"; + export default function UserNotices() { - return Użytkownik; -} + const { notices, fetchNotices } = useNoticesStore(); + const [isLoading, setIsLoading] = useState(true); + const currentUserId = 1; // Tymczasowo, do czasu zaimplementowania logowania bo nie moge pobrac usera + + useEffect(() => { + const loadNotices = async () => { + setIsLoading(true); + try { + await fetchNotices(); + } catch (err) { + console.error("Błąd podczas pobierania ogłoszeń:", err); + } finally { + setIsLoading(false); + } + }; + loadNotices(); + }, []); + + const userNotices = notices.filter(notice => notice.clientId === currentUserId); + + if (isLoading) { + return ; + } + + return ( + + Moje ogłoszenia + {userNotices.length > 0 ? ( + ( + + + + + + + + )} + keyExtractor={(item) => item.noticeId.toString()} + /> + ) : ( + Nie masz żadnych ogłoszeń. + )} + + ); +} \ No newline at end of file From f6065893d03ea95affb876f4f9bf66ad20b2e8a9 Mon Sep 17 00:00:00 2001 From: Kuba Date: Tue, 3 Jun 2025 22:21:39 +0200 Subject: [PATCH 9/9] better look for account --- .../app/(tabs)/dashboard/account.jsx | 86 +++++++++++++------ 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/ArtisanConnect/app/(tabs)/dashboard/account.jsx b/ArtisanConnect/app/(tabs)/dashboard/account.jsx index 25d74a6..91b111d 100644 --- a/ArtisanConnect/app/(tabs)/dashboard/account.jsx +++ b/ArtisanConnect/app/(tabs)/dashboard/account.jsx @@ -1,5 +1,5 @@ import { Link } from "expo-router"; -import {Button} from "react-native"; +import {Pressable} from "react-native"; import {Box} from "@/components/ui/box"; import {Text} from "@/components/ui/text"; import {VStack} from "@/components/ui/vstack"; @@ -7,11 +7,12 @@ import {Image} from "@/components/ui/image"; import {ActivityIndicator, } from "react-native"; import {useEffect, useState} from "react"; import {getUserById} from "@/api/client"; +import {HStack} from "@gluestack-ui/themed"; export default function Account() { const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(true); - const currentUserId = 1; // Tymczasowo, do czasu zaimplementowania logowania bo nie moge pobrac usera + const currentUserId = 2; // Tymczasowo, do czasu zaimplementowania logowania bo nie moge pobrac usera useEffect(() => { const fetchUser = async () => { @@ -37,34 +38,67 @@ export default function Account() { } return ( - - - Zdjęcie profilowe - + + + + Zdjęcie profilowe + + + {user.firstName} {user.lastName} - - - - - Moje ogłoszenia - - - Moje płatności - + console.log("Edytuj dane użytkownika")} + > + Edytuj profil + + + + Moje dane + + + E-mail + {user.email || "brak danych"} + + + + + + Moje konto + + + + Moje ogłoszenia + + + + + {/*Tak dodałem, można zmienić na coś innego*/} + + + Historia płatności + + + + + + Ustawienia powiadomień + + + + + + Wyloguj się + ); } \ No newline at end of file