eletrotupi / tcc/ frontend/lib/api.tsad585119b1dc0fe5e5b988eb0d19bd01b466829c
3.2 KB | 129 lines Raw
1
import * as SecureStore from 'expo-secure-store';
2

3
const API_BASE_URL = process.env.EXPO_PUBLIC_API_BASE_URL;
4
const TOKEN_KEY = process.env.EXPO_PUBLIC_TOKEN_KEY; // Gary B.B Coleman fucking slaps
5

6
export interface User {
7
  id: number;
8
  email: string;
9
  firstName: string;
10
  lastName?: string;
11
}
12

13
export interface AuthResponse {
14
  token: string;
15
  user: User;
16
}
17

18
class ApiClient {
19
  private async getStoredToken(): Promise<string | null> {
20
    try {
21
      return await SecureStore.getItemAsync(TOKEN_KEY);
22
    } catch (error) {
23
      console.error('Failed to get stored token:', error);
24
      return null;
25
    }
26
  }
27

28
  private async storeToken(token: string): Promise<void> {
29
    try {
30
      await SecureStore.setItemAsync(TOKEN_KEY, token);
31
    } catch (error) {
32
      console.error('Failed to store token:', error);
33
      throw error;
34
    }
35
  }
36

37
  private async removeToken(): Promise<void> {
38
    try {
39
      await SecureStore.deleteItemAsync(TOKEN_KEY);
40
    } catch (error) {
41
      console.error('Failed to remove token:', error);
42
    }
43
  }
44

45
  private async request<T>(
46
    endpoint: string,
47
    options: RequestInit = {}
48
  ): Promise<T> {
49
    const token = await this.getStoredToken();
50

51
    const config: RequestInit = {
52
      ...options,
53
      headers: {
54
        'Content-Type': 'application/json',
55
        ...(token && { Authorization: `Bearer ${token}` }),
56
        ...options.headers,
57
      },
58
    };
59

60
    const response = await fetch(`${API_BASE_URL}${endpoint}`, config);
61

62
    if (!response.ok) {
63
      const error = await response.json().catch(() => ({ error: 'Network error' }));
64
      throw new Error(error.error || `HTTP ${response.status}`);
65
    }
66

67
    return response.json();
68
  }
69

70
  async login(email: string, password: string): Promise<AuthResponse> {
71
    const response = await this.request<AuthResponse>('/auth/login', {
72
      method: 'POST',
73
      body: JSON.stringify({ email, password }),
74
    });
75

76
    await this.storeToken(response.token);
77
    return response;
78
  }
79

80
  async signup(userData: {
81
    first_name: string;
82
    last_name?: string;
83
    email: string;
84
    password: string;
85
  }): Promise<AuthResponse> {
86
    const response = await this.request<AuthResponse>('/users', {
87
      method: 'POST',
88
      body: JSON.stringify(userData),
89
    });
90

91
    await this.storeToken(response.token);
92
    return response;
93
  }
94

95
  async forgotPassword(email: string): Promise<{ message: string; token?: string }> {
96
    return this.request('/auth/forgot-password', {
97
      method: 'POST',
98
      body: JSON.stringify({ email }),
99
    });
100
  }
101

102
  async resetPassword(token: string, password: string): Promise<{ message: string }> {
103
    return this.request('/auth/reset-password', {
104
      method: 'POST',
105
      body: JSON.stringify({ token, password }),
106
    });
107
  }
108

109
  async verifyToken(): Promise<{ valid: boolean; userId?: number; email?: string }> {
110
    try {
111
      return await this.request('/auth/verify');
112
    } catch (error) {
113
      // Token is invalid or expired
114
      await this.removeToken();
115
      throw error;
116
    }
117
  }
118

119
  async logout(): Promise<void> {
120
    await this.removeToken();
121
  }
122

123
  async getStoredAuthData(): Promise<{ token: string | null }> {
124
    const token = await this.getStoredToken();
125
    return { token };
126
  }
127
}
128

129
export const apiClient = new ApiClient();