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/(tabs)/dashboard/account.jsx b/ArtisanConnect/app/(tabs)/dashboard/account.jsx
index a6bff6d..1b770e5 100644
--- a/ArtisanConnect/app/(tabs)/dashboard/account.jsx
+++ b/ArtisanConnect/app/(tabs)/dashboard/account.jsx
@@ -1,16 +1,105 @@
+import { Link } from "expo-router";
+import { Pressable } from "react-native";
+import { Box } from "@/components/ui/box";
import { Text } from "@/components/ui/text";
-import { View } from "react-native";
-import { Button, ButtonText } from "@gluestack-ui/themed";
-import { useAuthStore } from "@/store/authStore";
+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";
+import { HStack } from "@gluestack-ui/themed";
-export default function User() {
- const signOut = useAuthStore((state) => state.signOut);
-
- return (
- Użytkownik
-
-
- )
+export default function Account() {
+ const [user, setUser] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const currentUserId = 2; // 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 (
+
+
+
+
+
+
+
+ {user.firstName} {user.lastName}
+
+
+ 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ę
+
+
+ );
}
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
diff --git a/ArtisanConnect/app/notice/[id].jsx b/ArtisanConnect/app/notice/[id].jsx
index 5847f79..f95f3c6 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,19 +6,50 @@ 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, TextInput} 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");
+
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 [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 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);
@@ -26,6 +57,16 @@ 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 () => {
@@ -53,8 +94,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");
@@ -69,6 +111,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 ;
}
@@ -93,24 +154,60 @@ export default function NoticeDetails() {
) : (
-
+
+ (
+
+
+
+ )}
+ keyExtractor={(item, index) => index.toString()}
+ />
+
+ {images.length > 1 && (
+
+ {images.map((_, index) => (
+
+ ))}
+
+ )}
+
)}
+
+ {formatDate(notice.publishDate)}
+
+
{notice.title}
-
-
- {notice.price}zł
+
+
+
+ Cena:
+ {notice.price} zł
+
{
if (isInWishlist) {
@@ -127,7 +224,108 @@ export default function NoticeDetails() {
/>
+
+
+ Kategoria: {notice.category}
+
+
+
+
+ Opis ogloszenia
+
+
+ {notice.description}
+
+
+
+
+
+ Uzytkownik:
+
+ {isUserLoading ? (
+
+ ) : user ? (
+ <>
+
+
+
+
+
+
+ {user.firstName} {user.lastName}
+
+
+ Email: {user.email}
+
+ 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
+
+
+
+
+ )}
+
);
}
\ No newline at end of file
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 (
+
+
+
+
+ {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