eletrotupi / tcc/ frontend/lib/api.ts02a7abe0f5af9cd206353ebb7cd528461b95aeb7
3.5 KB | 145 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
  updatedAt: Date;
12
}
13

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

19
export interface UserUpdateResponse {
20
  user: User
21
}
22

23
class ApiClient {
24
  private async getStoredToken(): Promise<string | null> {
25
    try {
26
      return await SecureStore.getItemAsync(TOKEN_KEY);
27
    } catch (error) {
28
      console.error('Failed to get stored token:', error);
29
      return null;
30
    }
31
  }
32

33
  private async storeToken(token: string): Promise<void> {
34
    try {
35
      await SecureStore.setItemAsync(TOKEN_KEY, token);
36
    } catch (error) {
37
      console.error('Failed to store token:', error);
38
      throw error;
39
    }
40
  }
41

42
  private async removeToken(): Promise<void> {
43
    try {
44
      await SecureStore.deleteItemAsync(TOKEN_KEY);
45
    } catch (error) {
46
      console.error('Failed to remove token:', error);
47
    }
48
  }
49

50
  private async request<T>(
51
    endpoint: string,
52
    options: RequestInit = {}
53
  ): Promise<T> {
54
    const token = await this.getStoredToken();
55

56
    const config: RequestInit = {
57
      ...options,
58
      headers: {
59
        'Content-Type': 'application/json',
60
        ...(token && { Authorization: `Bearer ${token}` }),
61
        ...options.headers,
62
      },
63
    };
64

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

67
    if (!response.ok) {
68
      const error = await response.json()
69
        .catch(() => ({ error: 'Network error' }));
70

71
      console.error("[API]: ", error, response.status)
72

73
      throw new Error(error.error || `HTTP ${response.status}`);
74
    }
75

76
    return response.json();
77
  }
78

79
  async login(email: string, password: string): Promise<AuthResponse> {
80
    const response = await this.request<AuthResponse>('/auth/login', {
81
      method: 'POST',
82
      body: JSON.stringify({ email, password }),
83
    });
84

85
    await this.storeToken(response.token);
86
    return response;
87
  }
88

89
  async signup(userData: {
90
    first_name: string;
91
    last_name?: string;
92
    email: string;
93
    password: string;
94
  }): Promise<AuthResponse> {
95
    const response = await this.request<AuthResponse>('/users', {
96
      method: 'POST',
97
      body: JSON.stringify(userData),
98
    });
99

100
    await this.storeToken(response.token);
101
    return response;
102
  }
103

104
  async forgotPassword(email: string): Promise<{ message: string; token?: string }> {
105
    return this.request('/auth/forgot-password', {
106
      method: 'POST',
107
      body: JSON.stringify({ email }),
108
    });
109
  }
110

111
  async resetPassword(token: string, password: string): Promise<{ message: string }> {
112
    return this.request('/auth/reset-password', {
113
      method: 'POST',
114
      body: JSON.stringify({ token, password }),
115
    });
116
  }
117

118
  async verifyToken(): Promise<{ valid: boolean; userId?: number; email?: string }> {
119
    try {
120
      return await this.request('/auth/verify');
121
    } catch (error) {
122
      // Token is invalid or expired
123
      await this.removeToken();
124
      throw error;
125
    }
126
  }
127

128
  async logout(): Promise<void> {
129
    await this.removeToken();
130
  }
131

132
  async getStoredAuthData(): Promise<{ token: string | null }> {
133
    const token = await this.getStoredToken();
134
    return { token };
135
  }
136

137
  async updateUser(user): Promise<void> {
138
    return await this.request(`/users/${user.id}`, {
139
      method: 'PUT',
140
      body: JSON.stringify({ user })
141
    })
142
  }
143
}
144

145
export const apiClient = new ApiClient();