source: petify-frontend/src/api/auth.ts

Last change on this file was 92e7c7a, checked in by veronika-ils <ilioskaveronika@…>, 10 hours ago

Petify fullstack project

  • Property mode set to 100644
File size: 3.9 KB
Line 
1export interface LoginRequest {
2 username: string
3 password: string
4}
5
6export interface SignupRequest {
7 username: string
8 email: string
9 password: string
10 firstName: string
11 lastName: string
12}
13
14export interface AuthResult {
15 token?: string
16 user?: {
17 userId: number
18 username: string
19 email: string
20 firstName: string
21 lastName: string
22 userType: string
23 verified: boolean
24 }
25 message?: string
26}
27
28function getBaseUrl(): string {
29 const base = (import.meta.env.VITE_API_BASE_URL as string | undefined) ?? ''
30 return base.replace(/\/$/, '')
31}
32
33function joinUrl(base: string, path: string): string {
34 if (!base) return path
35 return `${base}${path.startsWith('/') ? '' : '/'}${path}`
36}
37
38function extractToken(data: unknown): string | null {
39 if (!data || typeof data !== 'object') return null
40 const rec = data as Record<string, unknown>
41 const candidates = [rec.token, rec.accessToken, rec.jwt, rec.idToken]
42 for (const c of candidates) {
43 if (typeof c === 'string' && c.trim()) return c
44 }
45 // Sometimes APIs wrap: { data: { token: '...' } }
46 const nested = rec.data
47 if (nested && typeof nested === 'object') {
48 const n = nested as Record<string, unknown>
49 const nestedCandidates = [n.token, n.accessToken, n.jwt, n.idToken]
50 for (const c of nestedCandidates) {
51 if (typeof c === 'string' && c.trim()) return c
52 }
53 }
54 return null
55}
56
57async function postJson<T>(path: string, body: unknown, options?: { signal?: AbortSignal }): Promise<T> {
58 const url = joinUrl(getBaseUrl(), path)
59 const res = await fetch(url, {
60 method: 'POST',
61 headers: {
62 'Content-Type': 'application/json',
63 Accept: 'application/json',
64 },
65 body: JSON.stringify(body),
66 signal: options?.signal,
67 })
68
69 const text = await res.text()
70 let json: unknown = null
71 try {
72 json = text ? (JSON.parse(text) as unknown) : null
73 } catch {
74 json = null
75 }
76
77 if (!res.ok) {
78 const message =
79 (json && typeof json === 'object' && typeof (json as any).message === 'string' && (json as any).message) ||
80 text ||
81 `Request failed (${res.status})`
82 throw new Error(message)
83 }
84
85 return json as T
86}
87
88export async function login(payload: LoginRequest, options?: { signal?: AbortSignal }): Promise<AuthResult> {
89 const data = await postJson<any>('/api/auth/login', payload, options)
90
91 // Check if there's an error message
92 if (data.message && data.message !== "Login successful") {
93 throw new Error(data.message)
94 }
95
96 // Extract user information from the response
97 if (data.userId && data.username) {
98 return {
99 user: {
100 userId: data.userId,
101 username: data.username,
102 email: data.email,
103 firstName: data.firstName,
104 lastName: data.lastName,
105 userType: data.userType,
106 verified: data.verified || false // Use verified status from API response
107 },
108 message: data.message
109 }
110 }
111
112 // If we don't get user data, something went wrong
113 throw new Error('Login failed: Invalid response from server')
114}
115
116export async function signup(payload: SignupRequest, options?: { signal?: AbortSignal }): Promise<AuthResult> {
117 const data = await postJson<any>('/api/auth/signup', payload, options)
118
119 // Check if there's an error message
120 if (data.message && data.message !== "User registered successfully") {
121 throw new Error(data.message)
122 }
123
124 // Extract user information from the response if successful
125 if (data.userId && data.username) {
126 return {
127 user: {
128 userId: data.userId,
129 username: data.username,
130 email: data.email,
131 firstName: data.firstName,
132 lastName: data.lastName,
133 userType: data.userType,
134 verified: data.verified || false // Use verified status from API response
135 },
136 message: data.message
137 }
138 }
139
140 // If registration was successful but no user data returned, that's okay
141 return { message: data.message || "Registration successful" }
142}
Note: See TracBrowser for help on using the repository browser.