From c19333ad8b39967caa52d5fc8e23a78c5ba387dd Mon Sep 17 00:00:00 2001 From: Patryk Date: Sat, 7 Jun 2025 23:08:21 +0200 Subject: [PATCH] fix login check and urls --- ArtisanConnect/api/categories.jsx | 25 +- ArtisanConnect/api/client.jsx | 19 +- ArtisanConnect/api/notices.jsx | 188 +++++++-------- ArtisanConnect/api/wishlist.jsx | 50 ++-- ArtisanConnect/app/(tabs)/_layout.jsx | 128 ++++++----- .../app/(tabs)/dashboard/_layout.jsx | 20 +- ArtisanConnect/app/(tabs)/index.jsx | 50 ++-- ArtisanConnect/components/CategorySection.jsx | 56 ++--- ArtisanConnect/components/UserSection.jsx | 47 ++-- ArtisanConnect/store/authStore.jsx | 215 ++++++++++-------- 10 files changed, 424 insertions(+), 374 deletions(-) diff --git a/ArtisanConnect/api/categories.jsx b/ArtisanConnect/api/categories.jsx index 82f4a49..ed76375 100644 --- a/ArtisanConnect/api/categories.jsx +++ b/ArtisanConnect/api/categories.jsx @@ -1,17 +1,16 @@ import axios from "axios"; -import {useAuthStore} from "@/store/authStore"; +import { useAuthStore } from "@/store/authStore"; -const API_URL = "https://testowe.zikor.pl/api/v1"; +const API_URL = "https://hopp.zikor.pl/api/v1"; export async function listCategories() { - - const { token } = useAuthStore.getState(); - const headers = token ? { 'Authorization': `Bearer ${token}` } : {}; - - try { - const response = await axios.get(`${API_URL}/vars/categories`, { headers }); - return response.data; - } catch (err) { - console.error("Nie udało się pobrać listy kategorii.", err.response.status); - } -} \ No newline at end of file + const { token } = useAuthStore.getState(); + const headers = token ? { Authorization: `Bearer ${token}` } : {}; + + try { + const response = await axios.get(`${API_URL}/vars/categories`, { headers }); + return response.data; + } catch (err) { + 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 6f0489c..6268c0e 100644 --- a/ArtisanConnect/api/client.jsx +++ b/ArtisanConnect/api/client.jsx @@ -1,13 +1,16 @@ import axios from "axios"; -const API_URL = "https://testowe.zikor.pl/api/v1"; +const API_URL = "https://hopp.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; - } + 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/api/notices.jsx b/ArtisanConnect/api/notices.jsx index 280ffbc..1153ea0 100644 --- a/ArtisanConnect/api/notices.jsx +++ b/ArtisanConnect/api/notices.jsx @@ -1,129 +1,133 @@ import axios from "axios"; -import FormData from 'form-data' -import {useAuthStore} from "@/store/authStore"; +import FormData from "form-data"; +import { useAuthStore } from "@/store/authStore"; -const API_URL = "https://testowe.zikor.pl/api/v1"; +const API_URL = "https://hopp.zikor.pl/api/v1"; //const API_URL = "http://10.0.2.2:8080/api/v1"; export async function listNotices() { - const { token } = useAuthStore.getState(); - const headers = token ? { 'Authorization': `Bearer ${token}` } : {}; + const { token } = useAuthStore.getState(); + const headers = token ? { Authorization: `Bearer ${token}` } : {}; - console.log(token); + console.log(token); - const response = await fetch(`${API_URL}/notices/get/all`, { - headers: headers - }); - console.log(response); - const data = await response.json(); - if (!response.ok) { - throw new Error(response.toString()); - } - return data; + const response = await fetch(`${API_URL}/notices/get/all`, { + headers: headers, + }); + // console.log(response);r + const data = await response.json(); + if (!response.ok) { + throw new Error(response.toString()); + } + return data; } export async function getNoticeById(noticeId) { - const response = await fetch(`${API_URL}/notices/get/${noticeId}`); + const response = await fetch(`${API_URL}/notices/get/${noticeId}`); - const data = await response.json(); - if (!response.ok) { - throw new Error("Error"); - } - return data; + const data = await response.json(); + if (!response.ok) { + throw new Error("Error"); + } + return data; } export async function createNotice(notice) { - try { - const response = await axios.post(`${API_URL}/notices/add`, notice, { - headers: { - "Content-Type": "application/json", - }, - }); + try { + const response = await axios.post(`${API_URL}/notices/add`, notice, { + headers: { + "Content-Type": "application/json", + }, + }); - if (response.data.noticeId !== null) { - for (const imageUri of notice.image) { - await uploadImage(response.data.noticeId, imageUri); - } - } - - return response.data; - } catch (error) { - console.log("Error", error.response.data, error.response.status); - return null; + if (response.data.noticeId !== null) { + for (const imageUri of notice.image) { + await uploadImage(response.data.noticeId, imageUri); + } } + + return response.data; + } catch (error) { + console.log("Error", error.response.data, error.response.status); + return null; + } } export async function getImageByNoticeId(noticeId) { - let imageUrl; - try { - const listResponse = await axios.get(`${API_URL}/images/list/${noticeId}`); + let imageUrl; + try { + const listResponse = await axios.get(`${API_URL}/images/list/${noticeId}`); - const imageName = listResponse.data[0]; - imageUrl = `${API_URL}/images/get/${imageName}`; + const imageName = listResponse.data[0]; + imageUrl = `${API_URL}/images/get/${imageName}`; - console.log(`Pobrano zdjęcie o nazwie: ${imageName}`); + console.log(`Pobrano zdjęcie o nazwie: ${imageName}`); - return imageUrl; - } catch (err) { - console.log(`Zdjęcie nie istnieje dla notice o id: ${noticeId}`); - imageUrl = "https://http.cat/404.jpg"; - return imageUrl; - } + return imageUrl; + } catch (err) { + console.log(`Zdjęcie nie istnieje dla notice o id: ${noticeId}`); + imageUrl = "https://http.cat/404.jpg"; + return imageUrl; + } } export async function getAllImagesByNoticeId(noticeId) { - try { - const listResponse = await axios.get(`${API_URL}/images/list/${noticeId}`); + try { + const listResponse = await axios.get(`${API_URL}/images/list/${noticeId}`); - if (listResponse.data && listResponse.data.length > 0) { - const imageUrls = listResponse.data.map(imageName => - `${API_URL}/images/get/${imageName}` - ); + if (listResponse.data && listResponse.data.length > 0) { + const imageUrls = listResponse.data.map( + (imageName) => `${API_URL}/images/get/${imageName}` + ); - // console.log(`Pobrano ${imageUrls.length} zdjęć dla ogłoszenia o id: ${noticeId}`); - return imageUrls; - } - - // console.log(`Brak zdjęć dla ogłoszenia o id: ${noticeId}`); - return ["https://http.cat/404.jpg"]; - } catch (err) { - // console.log(`Błąd podczas pobierania listy zdjęć dla ogłoszenia o id: ${noticeId}`, err); - return ["https://http.cat/404.jpg"]; + // console.log(`Pobrano ${imageUrls.length} zdjęć dla ogłoszenia o id: ${noticeId}`); + return imageUrls; } + + // console.log(`Brak zdjęć dla ogłoszenia o id: ${noticeId}`); + return ["https://http.cat/404.jpg"]; + } catch (err) { + // console.log(`Błąd podczas pobierania listy zdjęć dla ogłoszenia o id: ${noticeId}`, err); + return ["https://http.cat/404.jpg"]; + } } export const uploadImage = async (noticeId, imageUri) => { - console.log(imageUri); + console.log(imageUri); - const formData = new FormData(); + const formData = new FormData(); - const filename = imageUri.split('/').pop(); + const filename = imageUri.split("/").pop(); - const match = /\.(\w+)$/.exec(filename); - const type = match ? `image/${match[1]}` : 'image/jpeg'; + const match = /\.(\w+)$/.exec(filename); + const type = match ? `image/${match[1]}` : "image/jpeg"; - formData.append('file', { - uri: imageUri, - name: filename, - type: type, - }); + formData.append("file", { + uri: imageUri, + name: filename, + type: type, + }); - try { - const response = await axios.post( - `${API_URL}/images/upload/${noticeId}`, - formData, - { - headers: { - 'Content-Type': 'multipart/form-data', - }, - } - ); - console.info('Upload successful:', response.data); - return response.data; - } catch (error) { - console.log("imageURI:", imageUri); - console.error('Error uploading image:', error.response.data, error.response.status); - throw error; - } -} \ No newline at end of file + try { + const response = await axios.post( + `${API_URL}/images/upload/${noticeId}`, + formData, + { + headers: { + "Content-Type": "multipart/form-data", + }, + } + ); + console.info("Upload successful:", response.data); + return response.data; + } catch (error) { + console.log("imageURI:", imageUri); + console.error( + "Error uploading image:", + error.response.data, + error.response.status + ); + throw error; + } +}; diff --git a/ArtisanConnect/api/wishlist.jsx b/ArtisanConnect/api/wishlist.jsx index 78d0d4d..265fc71 100644 --- a/ArtisanConnect/api/wishlist.jsx +++ b/ArtisanConnect/api/wishlist.jsx @@ -1,34 +1,38 @@ import axios from "axios"; -import {useAuthStore} from "@/store/authStore"; +import { useAuthStore } from "@/store/authStore"; // import FormData from 'form-data' -const API_URL = "https://testowe.zikor.pl/api/v1/wishlist"; +const API_URL = "https://hopp.zikor.pl/api/v1/wishlist"; export async function toggleNoticeStatus(noticeId) { - const { token } = useAuthStore.getState(); - const headers = token ? { 'Authorization': `Bearer ${token}` } : {}; + const { token } = useAuthStore.getState(); + const headers = token ? { Authorization: `Bearer ${token}` } : {}; - try { - const response = await axios.post(`${API_URL}/toggle/${noticeId}`, {}, { - headers - }); - return response.data; - } catch (error) { - console.error("Error toggling wishlist item:", error); - throw error; - } + try { + const response = await axios.post( + `${API_URL}/toggle/${noticeId}`, + {}, + { + headers, + } + ); + return response.data; + } catch (error) { + console.error("Error toggling wishlist item:", error); + throw error; + } } export async function getWishlist() { - const { token } = useAuthStore.getState(); - const headers = token ? { 'Authorization': `Bearer ${token}` } : {}; + const { token } = useAuthStore.getState(); + const headers = token ? { Authorization: `Bearer ${token}` } : {}; - try { - const response = await axios.get(`${API_URL}/`, {headers}); - console.log("Wishlist response:", response.data); - return response.data; - } catch (error) { - console.error("Error fetching wishlist:", error); - throw error; - } + try { + const response = await axios.get(`${API_URL}/`, { headers }); + console.log("Wishlist response:", response.data); + return response.data; + } catch (error) { + console.error("Error fetching wishlist:", error); + throw error; + } } diff --git a/ArtisanConnect/app/(tabs)/_layout.jsx b/ArtisanConnect/app/(tabs)/_layout.jsx index 7f9d212..4a42cf7 100644 --- a/ArtisanConnect/app/(tabs)/_layout.jsx +++ b/ArtisanConnect/app/(tabs)/_layout.jsx @@ -1,64 +1,70 @@ -import {Tabs} from "expo-router"; -import {Ionicons} from "@expo/vector-icons"; +import { Tabs, Redirect } from "expo-router"; +import { Ionicons } from "@expo/vector-icons"; +import { useAuthStore } from "@/store/authStore"; export default function TabLayout() { - return ( - - ( - - ), - }} - /> - ( - - ), - }} - /> - ( - - ), - }} - /> - ( - - ), - }} - /> - ( - - ), - }} - /> - - ); + const token = useAuthStore((state) => state.token); + + if (!token) { + return ; + } + return ( + + ( + + ), + }} + /> + ( + + ), + }} + /> + ( + + ), + }} + /> + ( + + ), + }} + /> + ( + + ), + }} + /> + + ); } diff --git a/ArtisanConnect/app/(tabs)/dashboard/_layout.jsx b/ArtisanConnect/app/(tabs)/dashboard/_layout.jsx index df44641..980668e 100644 --- a/ArtisanConnect/app/(tabs)/dashboard/_layout.jsx +++ b/ArtisanConnect/app/(tabs)/dashboard/_layout.jsx @@ -1,6 +1,15 @@ +import { DrawerItem } from "@react-navigation/drawer"; import { Drawer } from "expo-router/drawer"; +import { useAuthStore } from "@/store/authStore"; + +import { + DrawerContentScrollView, + DrawerItemList, +} from "@react-navigation/drawer"; export default function AccountDrawerLayout() { + const signOut = useAuthStore((state) => state.signOut); + return ( ( + + + + + )} > state.token); + const token = useAuthStore((state) => state.token); const router = useRouter(); const [isReady, setIsReady] = useState(false); - const fetchNotices = useNoticesStore((state) => state.fetchNotices); + const fetchNotices = useNoticesStore((state) => state.fetchNotices); useEffect(() => { setIsReady(true); @@ -27,36 +26,41 @@ const token = useAuthStore((state) => state.token); } }, [isReady, token, router]); - useEffect(() => { if (token) { - fetchNotices(); - } -}, [token, fetchNotices]); - + fetchNotices(); + } + }, [token, fetchNotices]); const notices = useNoticesStore((state) => state.notices); - // console.log("Notices:", notices); - + // console.log("Notices:", notices); + const latestNotices = [...notices] .sort((a, b) => new Date(b.publishDate) - new Date(a.publishDate)) .slice(0, 6); - const recomendedNotices = [...notices] + const recomendedNotices = [...notices] .sort(() => Math.random() - 0.5) .slice(0, 6); - return ( - - {/* */} - - + + {/* */} + + - + - - - {/* */} - + + + {/* */} + ); } diff --git a/ArtisanConnect/components/CategorySection.jsx b/ArtisanConnect/components/CategorySection.jsx index 7698adc..2d9321e 100644 --- a/ArtisanConnect/components/CategorySection.jsx +++ b/ArtisanConnect/components/CategorySection.jsx @@ -1,32 +1,25 @@ -import { View, FlatList} from 'react-native'; -import { useEffect, useState } from 'react' +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'; -import { Pressable } from '@/components/ui/pressable'; -// import axios from 'axios'; -import {listCategories} from "@/api/categories"; +import { Heading } from "@/components/ui/heading"; +import { Text } from "@/components/ui/text"; +import { Link } from "expo-router"; +import { Pressable } from "@/components/ui/pressable"; +import { listCategories } from "@/api/categories"; - -export function CategorySection({notices, title}) { - const token = useAuthStore((state) => state.token); - +export function CategorySection({ notices, title }) { const [categoryMap, setCategoryMap] = useState({}); useEffect(() => { - if(token){ const fetchCategories = async () => { - let data = await listCategories(); - if (Array.isArray(data)) { - setCategoryMap(data); - } - } + let data = await listCategories(); + if (Array.isArray(data)) { + setCategoryMap(data); + } + }; fetchCategories(); - } - }, [token]); - + }); const categories = Array.from( new Set(notices.map((notice) => notice.category)) @@ -35,13 +28,11 @@ export function CategorySection({notices, title}) { const getCount = (category) => notices.filter((notice) => notice.category === category).length; - console.log("CategoryMap:", categoryMap); - - if(!categoryMap) { - return null; + if (!categoryMap || Object.keys(categoryMap).length === 0) { + return null; } -return ( + return ( {title} cat.value === item); return ( - - - {categoryObj ? categoryObj.label : item} ({getCount(item)}) - - + + + {categoryObj ? categoryObj.label : item} ({getCount(item)}) + + ); }} /> ); - -} \ No newline at end of file +} diff --git a/ArtisanConnect/components/UserSection.jsx b/ArtisanConnect/components/UserSection.jsx index 69ea77e..7cd6c61 100644 --- a/ArtisanConnect/components/UserSection.jsx +++ b/ArtisanConnect/components/UserSection.jsx @@ -1,27 +1,27 @@ -import { View} from 'react-native'; -import { useEffect, useState } from 'react' -import { Heading } from '@/components/ui/heading'; -import { FlatList } from 'react-native'; -import axios from 'axios'; -import UserBlock from '@/components/UserBlock'; -import {useAuthStore} from "@/store/authStore"; +import { View } from "react-native"; +import { useEffect, useState } from "react"; +import { Heading } from "@/components/ui/heading"; +import { FlatList } from "react-native"; +import axios from "axios"; +import UserBlock from "@/components/UserBlock"; +import { useAuthStore } from "@/store/authStore"; - -export function UserSection({notices, title}) { - const token = useAuthStore((state) => state.token); - const headers = token ? { 'Authorization': `Bearer ${token}` } : {}; - const [users, setUsers] = useState([]); +export function UserSection({ notices, title }) { + const token = useAuthStore((state) => state.token); + const headers = token ? { Authorization: `Bearer ${token}` } : {}; + const [users, setUsers] = useState([]); useEffect(() => { - if (token){ - axios.get('https://testowe.zikor.pl/api/v1/clients/get/all', { headers }) - .then(res => setUsers(res.data)) - .catch(() => setUsers([])); + if (token) { + axios + .get("https://hopp.zikor.pl/api/v1/clients/get/all", { headers }) + .then((res) => setUsers(res.data)) + .catch(() => setUsers([])); } }, [token]); - - const usersWithNoticeCount = users.map(user => { - const count = notices.filter(n => n.clientId === user.id).length; + + const usersWithNoticeCount = users.map((user) => { + const count = notices.filter((n) => n.clientId === user.id).length; return { ...user, noticeCount: count }; }); @@ -29,7 +29,7 @@ export function UserSection({notices, title}) { .sort((a, b) => b.noticeCount - a.noticeCount) .slice(0, 5); -return ( + return ( {title} { - return ( - - ); + return ; }} /> ); - -} \ No newline at end of file +} diff --git a/ArtisanConnect/store/authStore.jsx b/ArtisanConnect/store/authStore.jsx index 0bb66c6..db4a099 100644 --- a/ArtisanConnect/store/authStore.jsx +++ b/ArtisanConnect/store/authStore.jsx @@ -1,110 +1,135 @@ -import {create} from "zustand"; -import {createJSONStorage, persist} from "zustand/middleware"; +import { create } from "zustand"; +import { createJSONStorage, persist } from "zustand/middleware"; import AsyncStorage from "@react-native-async-storage/async-storage"; import axios from "axios"; -const API_URL = "https://testowe.zikor.pl/api/v1"; +const API_URL = "https://hopp.zikor.pl/api/v1"; export const useAuthStore = create( - persist( - (set) => ({ - user: null, - token: null, - isLoading: false, - error: null, + persist( + (set, get) => { + if (!axios.interceptors.response.handlers.length) { + axios.interceptors.response.use( + (response) => response, + (error) => { + if ( + (error.response && error.response.status === 401) || + error.response.status === 403 + ) { + set({ user: null, token: null, isLoading: false }); + delete axios.defaults.headers.common["Authorization"]; + } + return Promise.reject(error); + } + ); + } - signIn: async (email, password) => { - set({isLoading: true, error: null}); - try { - const response = await axios.post(`${API_URL}/auth/login`, { - email, - password - }); + return { + user: null, + token: null, + isLoading: false, + error: null, - const user = response.data.user; - const token = response.data.token; - set({user, token, isLoading: false}); - } catch (error) { - set({error: error.response?.data?.message || error.message, isLoading: false}); - throw error; - } - }, + signIn: async (email, password) => { + set({ isLoading: true, error: null }); + try { + const response = await axios.post(`${API_URL}/auth/login`, { + email, + password, + }); - signUp: async (userData) => { - set({isLoading: true, error: null}); - try { - console.log(userData); + const user = response.data.user; + const token = response.data.token; + set({ user, token, isLoading: false }); + axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; + } catch (error) { + set({ + error: error.response?.data?.message || error.message, + isLoading: false, + }); + throw error; + } + }, - const response = await axios.post(`${API_URL}/auth/register`, userData, { - headers: {'Content-Type': 'application/json'} - }); + signUp: async (userData) => { + set({ isLoading: true, error: null }); + try { + const response = await axios.post( + `${API_URL}/auth/register`, + userData, + { + headers: { "Content-Type": "application/json" }, + } + ); - console.log(response.data); + const user = response.data.user; + const token = response.data.token; + set({ user, token, isLoading: false }); + axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; + return user; + } catch (error) { + set({ + error: error.response?.data?.message || error.message, + isLoading: false, + }); + throw error; + } + }, - const user = response.data.user; - const token = response.data.token; - set({user, token, isLoading: false}); + signInWithGoogle: async (googleToken) => { + set({ isLoading: true, error: null }); + try { + const response = await axios.post(`${API_URL}/auth/google`, { + token: googleToken, + }); - return user; - } catch (error) { - set({error: error.response?.data?.message || error.message, isLoading: false}); - throw error; - } - }, + const { user, token } = response.data; + set({ user, token, isLoading: false }); + axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; + return user; + } catch (error) { + set({ + error: error.response?.data?.message || error.message, + isLoading: false, + }); + throw error; + } + }, - signInWithGoogle: async (googleToken) => { - set({isLoading: true, error: null}); - try { - const response = await axios.post(`${API_URL}/auth/google`, {token: googleToken}); + signOut: async () => { + try { + const { token } = get(); + const headers = token ? { Authorization: `Bearer ${token}` } : {}; + await axios.post(`${API_URL}/auth/logout`, {}, { headers }); + } catch (error) { + // console.error("Logout error:", error); + } finally { + delete axios.defaults.headers.common["Authorization"]; + set({ user: null, token: null, isLoading: false }); + } + }, - const {user, token} = response.data; - set({user, token, isLoading: false}); + checkAuth: async () => { + const { token } = get(); + if (!token) return null; - axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; - - return user; - } catch (error) { - set({error: error.response?.data?.message || error.message, isLoading: false}); - throw error; - } - }, - - signOut: async () => { - try { - const {token} = useAuthStore.getState(); - const headers = token ? { 'Authorization': `Bearer ${token}` } : {}; - // Можно отправить запрос на бэкенд для инвалидации токена - await axios.post(`${API_URL}/auth/logout`, {}, { headers }); - } catch (error) { - console.error("Logout error:", error); - } finally { - delete axios.defaults.headers.common["Authorization"]; - set({user: null, token: null}); - } - }, - - checkAuth: async () => { - const {token} = useAuthStore.getState(); - if (!token) return null; - - set({isLoading: true}); - try { - axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; - - const response = await axios.get(`${API_URL}/auth/me`); - - set({user: response.data, isLoading: false}); - return response.data; - } catch (error) { - delete axios.defaults.headers.common["Authorization"]; - set({user: null, token: null, isLoading: false}); - return null; - } - }, - }), - { - name: "auth-storage", - storage: createJSONStorage(() => AsyncStorage), - } - ) -); \ No newline at end of file + set({ isLoading: true }); + try { + axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; + const response = await axios.get(`${API_URL}/auth/me`); + set({ user: response.data, isLoading: false }); + return response.data; + } catch (error) { + delete axios.defaults.headers.common["Authorization"]; + set({ user: null, token: null, isLoading: false }); + return null; + } + }, + }; + }, + { + name: "auth-storage", + storage: createJSONStorage(() => AsyncStorage), + } + ) +);