eletrotupi / tcc/ frontend/lib/api.ts7822d9e99b09af4dfe1e8e53c16fa9ec92016599
4.1 KB | 170 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
  avatarKey?: string;
13
  avatarURL?: string;
14
}
15

16
export interface AuthResponse {
17
  token: string;
18
  user: User;
19
}
20

21
export interface UserUpdateResponse {
22
  user: User
23
}
24

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

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

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

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

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

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

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

73
      console.error("[API]: ", error, response.status)
74

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

78
    return response.json();
79
  }
80

81
  async avatar(formData: FormData): Promise<void> {
82
    return await this.request(`/users/me/avatar`, {
83
      method: 'POST',
84
      body: formData,
85
      headers: {
86
        'Content-Type': 'multipart/form-data',
87
      } as any,
88
    })
89
  }
90

91
  async removeAvatar(): Promise<void> {
92
    return await this.request(`/users/me/avatar`, {
93
      method: 'DELETE'
94
    });
95
  }
96

97
  async login(email: string, password: string): Promise<AuthResponse> {
98
    const response = await this.request<AuthResponse>('/auth/login', {
99
      method: 'POST',
100
      body: JSON.stringify({ email, password }),
101
    });
102

103
    await this.storeToken(response.token);
104
    return response;
105
  }
106

107
  async signup(userData: {
108
    first_name: string;
109
    last_name?: string;
110
    email: string;
111
    password: string;
112
  }): Promise<AuthResponse> {
113
    const response = await this.request<AuthResponse>('/users', {
114
      method: 'POST',
115
      body: JSON.stringify(userData),
116
    });
117

118
    await this.storeToken(response.token);
119
    return response;
120
  }
121

122
  async forgotPassword(email: string): Promise<{ message: string; token?: string }> {
123
    return this.request('/auth/forgot-password', {
124
      method: 'POST',
125
      body: JSON.stringify({ email }),
126
    });
127
  }
128

129
  async resetPassword(token: string, password: string): Promise<{ message: string }> {
130
    return this.request('/auth/reset-password', {
131
      method: 'POST',
132
      body: JSON.stringify({ token, newPassword: password }),
133
    });
134
  }
135

136
  async verifyToken(): Promise<{ valid: boolean; userId?: number; email?: string }> {
137
    try {
138
      return await this.request('/auth/verify');
139
    } catch (error) {
140
      // Token is invalid or expired
141
      await this.removeToken();
142
      throw error;
143
    }
144
  }
145

146
  async logout(): Promise<void> {
147
    await this.removeToken();
148
  }
149

150
  async getStoredAuthData(): Promise<{ token: string | null }> {
151
    const token = await this.getStoredToken();
152
    return { token };
153
  }
154

155
  async updateUser(user): Promise<void> {
156
    return await this.request(`/users/${user.id}`, {
157
      method: 'PUT',
158
      body: JSON.stringify({ user })
159
    })
160
  }
161

162
  async createMoodEntry(moodEntry): Promise<void> {
163
    return await this.request(`/moods`, {
164
      method: 'POST',
165
      body: JSON.stringify({ mood: moodEntry })
166
    })
167
  }
168
}
169

170
export const apiClient = new ApiClient();