diff --git a/src/components/Login.tsx b/src/components/Login.tsx index 12659d5..0426fb6 100644 --- a/src/components/Login.tsx +++ b/src/components/Login.tsx @@ -26,6 +26,7 @@ interface AuthResponse { record: UserRecord; } + const LoginPage = () => { const [email, setEmail] = useState('suvodip@siliconpin.com'); const [password, setPassword] = useState('Simple2pass'); @@ -35,18 +36,30 @@ const LoginPage = () => { const pb = new PocketBase("https://tst-pb.s38.siliconpin.com"); + interface AuthResponse { + token: string; + record: { + query: string; + id: string; + email: string; + name: string; + avatar: string; + }; + } + const handleSubmit = async (e: FormEvent) => { e.preventDefault(); setIsLoading(true); setStatus({ message: '', isError: false }); - + try { const authData = await pb.collection("users").authWithPassword(email, password); - + const avatarUrl = authData.record.avatar ? pb.files.getUrl(authData.record, authData.record.avatar) : ''; + const authResponse: AuthResponse = { token: authData.token, record: { - query: 'new', + query: 'new', id: authData.record.id, email: authData.record.email, name: authData.record.name || '', @@ -54,8 +67,8 @@ const LoginPage = () => { } }; - await syncSessionWithBackend(authResponse); - // window.location.href = '/profile'; + await syncSessionWithBackend(authResponse, avatarUrl); + window.location.href = '/profile'; } catch (error) { console.error("Login failed:", error); setStatus({ @@ -77,20 +90,21 @@ const LoginPage = () => { if (!authData?.record) { throw new Error("No user record found"); } - + + const avatarUrl = authData.record.avatar ? pb.files.getUrl(authData.record, authData.record.avatar) : ''; const authResponse: AuthResponse = { token: authData.token, record: { - query: 'new', - id: authData.record.id, - email: authData.record.email || '', - name: authData.record.name || '', - avatar: authData.record.avatar || '' + query: 'new', + id: authData.record.id, + email: authData.record.email || '', + name: authData.record.name || '', + avatar: authData.record.avatar || '' } }; - await syncSessionWithBackend(authResponse); - // window.location.href = '/profile'; + await syncSessionWithBackend(authResponse, avatarUrl); + window.location.href = '/profile'; } catch (error) { console.error(`${provider} Login failed:`, error); setStatus({ @@ -101,33 +115,35 @@ const LoginPage = () => { setIsLoading(false); } }; - -const syncSessionWithBackend = async (authData: AuthResponse) => { - try { - const response = await fetch('http://localhost:2058/host-api/v1/users/session/', { - method: 'POST', - credentials: 'include', // Crucial for cookies - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - accessToken: authData.token, - email: authData.record.email, - name: authData.record.name, - avatar: authData.record.avatar - ? pb.files.getUrl(authData.record, authData.record.avatar) - : '', - isAuthenticated: true, - id: authData.record.id - }) - }); - - if (!response.ok) throw new Error('Failed to sync session'); - - const data = await response.json(); - console.log('Session synced:', data); - } catch (error) { - console.error('Error syncing session:', error); - } -}; + + const syncSessionWithBackend = async (authData: AuthResponse, avatarUrl: string) => { + try { + const response = await fetch('http://localhost:2058/host-api/v1/users/session/', { + method: 'POST', + credentials: 'include', // Important for cookies + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + query: 'new', + accessToken: authData.token, + email: authData.record.email, + name: authData.record.name, + avatar: avatarUrl, + isAuthenticated: true, + id: authData.record.id + }) + }); + + if (!response.ok) { + throw new Error('Failed to sync session'); + } + + const data = await response.json(); + console.log('Session synced with backend:', data); + } catch (error) { + console.error('Error syncing session:', error); + throw error; // Re-throw the error if you want calling functions to handle it + } + }; return (
diff --git a/src/components/UpdateAvatar.tsx b/src/components/UpdateAvatar.tsx new file mode 100644 index 0000000..86d54f3 --- /dev/null +++ b/src/components/UpdateAvatar.tsx @@ -0,0 +1,52 @@ +import { useState, useRef } from 'react'; +import { Button } from "./ui/button"; +import { Input } from "./ui/input"; +import { Label } from "./ui/label"; +import { X } from "lucide-react"; // Import an icon for the remove button + +export function AvatarUpload() { + const [selectedFile, setSelectedFile] = useState(null); + const fileInputRef = useRef(null); + + const handleFileChange = (e: React.ChangeEvent) => { + if (e.target.files && e.target.files.length > 0) { + setSelectedFile(e.target.files[0]); + } + }; + const handleRemoveFile = () => { + setSelectedFile(null); + if (fileInputRef.current) { + fileInputRef.current.value = ''; // Reset file input + } + }; + return ( +
+ {!selectedFile ? ( +
+
+ + + +
+

+ JPG, GIF or PNG. 1MB max. +

+
+ ) : ( +
+
+

{selectedFile.name}

+

{(selectedFile.size / 1024).toFixed(2)} KB

+
+ + +
+ )} +
+ ); +} +export default AvatarUpload; \ No newline at end of file diff --git a/src/components/UserProfile.tsx b/src/components/UserProfile.tsx index 4e7f83c..95ff65f 100644 --- a/src/components/UserProfile.tsx +++ b/src/components/UserProfile.tsx @@ -7,6 +7,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from ". import { Separator } from "./ui/separator"; import { Textarea } from "./ui/textarea"; import React, { useState, useEffect } from 'react'; +import UpdateAvatar from './UpdateAvatar'; interface SessionData { [key: string]: any; @@ -21,6 +22,7 @@ interface UserData { export default function ProfilePage() { const [userData, setUserData] = useState(null); + const [invoiceList, setInvoiceList] = useState([]); const [error, setError] = useState(null); useEffect(() => { @@ -45,8 +47,36 @@ export default function ProfilePage() { throw error; } }; + const getInvoiceListData = async () => { + try { + const response = await fetch('http://localhost:2058/host-api/v1/invoice/invoice-info/', { + method: 'GET', + credentials: 'include', // Crucial for cookies + headers: { 'Accept': 'application/json' } + }); + + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + + const data = await response.json(); + + if (!data.success) { + throw new Error(data.message || 'Session fetch failed'); + } + + setInvoiceList(data.data); // Fix: Use `data.data` instead of `data` + return data.data; // Fix: `session_data` does not exist in response + } catch (error) { + console.error('Fetch error:', error); + throw error; + } + }; + + fetchSessionData(); + getInvoiceListData(); }, []); if (error) { @@ -58,12 +88,10 @@ export default function ProfilePage() { } return (
-
+ {/*

Profile

-

- Update your profile settings. -

-
+

Update your profile settings.

+
*/}
@@ -80,14 +108,8 @@ export default function ProfilePage() { JP -
- -

- JPG, GIF or PNG. 1MB max. -

-
+ +
@@ -106,7 +128,7 @@ export default function ProfilePage() {
-
+ {/*