-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathapiClient.ts
More file actions
188 lines (165 loc) · 5.24 KB
/
apiClient.ts
File metadata and controls
188 lines (165 loc) · 5.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import axios, { type AxiosInstance } from 'axios';
const defaultBaseUrl = import.meta.env.VITE_API_BASE_URL ?? '';
export type DonationCreateRequest = {
firstName: string;
lastName: string;
email: string;
amount: number; // parsed to number in the form
isAnonymous: boolean;
donationType: 'one_time' | 'recurring';
dedicationMessage: string; // allow '' from ui
showDedicationPublicly: boolean;
recurringInterval?: 'weekly' | 'monthly' | 'yearly';
};
export type CreateDonationResponse = { id: string };
export type SignInRequest = { email: string; password: string };
export type SignUpRequest = {
firstName: string;
lastName: string;
email: string;
password: string;
};
export type AuthResponse = {
accessToken: string;
refreshToken: string;
idToken: string;
};
export type RefreshRequest = { refreshToken: string; userSub: string };
export type ConfirmPasswordRequest = {
email: string;
confirmationCode: string;
newPassword: string;
};
type ApiError = { error?: string; message?: string };
export class ApiClient {
private axiosInstance: AxiosInstance;
constructor() {
this.axiosInstance = axios.create({ baseURL: defaultBaseUrl });
}
public async getHello(): Promise<string> {
//return this.get('/api') as Promise<string>;
const res = await this.axiosInstance.get<string>('/api');
return res.data;
}
public setAuthToken(token: string | null) {
if (token) {
this.axiosInstance.defaults.headers.common['Authorization'] =
`Bearer ${token}`;
} else {
delete this.axiosInstance.defaults.headers.common['Authorization'];
}
}
public async signin(body: SignInRequest): Promise<AuthResponse> {
try {
const res = await this.axiosInstance.post('/api/auth/signin', body);
return res.data as AuthResponse;
} catch (err: unknown) {
this.handleAxiosError(err, 'Failed to sign in');
}
}
public async signup(body: SignUpRequest): Promise<unknown> {
try {
const res = await this.axiosInstance.post('/api/auth/signup', body);
return res.data;
} catch (err: unknown) {
this.handleAxiosError(err, 'Failed to sign up');
}
}
public async refresh(body: RefreshRequest): Promise<AuthResponse> {
try {
const res = await this.axiosInstance.post('/api/auth/refresh', body);
return res.data as AuthResponse;
} catch (err: unknown) {
this.handleAxiosError(err, 'Failed to refresh token');
}
}
public async forgotPassword(email: string): Promise<void> {
try {
await this.axiosInstance.post('/api/auth/forgotPassword', { email });
} catch (err: unknown) {
this.handleAxiosError(err, 'Failed to send password reset email');
}
}
public async confirmPassword(body: ConfirmPasswordRequest): Promise<void> {
try {
await this.axiosInstance.post('/api/auth/confirmPassword', body);
} catch (err: unknown) {
this.handleAxiosError(err, 'Failed to reset password');
}
}
private handleAxiosError(err: unknown, defaultMsg: string): never {
if (axios.isAxiosError<ApiError>(err)) {
const data = err.response?.data;
const msg = data?.message ?? data?.error ?? err.message ?? defaultMsg;
throw new Error(msg);
}
throw new Error(defaultMsg);
}
public async createDonation(
body: DonationCreateRequest,
): Promise<CreateDonationResponse> {
try {
const res = await this.axiosInstance.post('/api/donations', body);
return res.data as CreateDonationResponse;
} catch (err: unknown) {
if (axios.isAxiosError<ApiError>(err)) {
const data = err.response?.data;
const msg =
data?.error ??
data?.message ??
err.message ??
'Failed to create donation';
throw new Error(msg);
}
throw new Error('Failed to create donation');
}
}
public async getDonations(params?: {
page?: number;
perPage?: number;
donationType?: 'one_time' | 'recurring';
status?: 'pending' | 'succeeded' | 'failed' | 'cancelled';
}): Promise<{
rows: Array<{
id: number;
firstName: string;
lastName: string;
email: string;
amount: number;
donationType: 'one_time' | 'recurring';
status: string;
createdAt: string;
}>;
total: number;
page: number;
perPage: number;
totalPages: number;
}> {
try {
const res = await this.axiosInstance.get('/api/donations', {
params,
});
return res.data;
} catch (err: unknown) {
this.handleAxiosError(err, 'Failed to fetch donations');
}
}
private async get(path: string): Promise<unknown> {
return this.axiosInstance.get(path).then((response) => response.data);
}
private async post(path: string, body: unknown): Promise<unknown> {
return this.axiosInstance
.post(path, body)
.then((response) => response.data);
}
private async patch(path: string, body: unknown): Promise<unknown> {
return this.axiosInstance
.patch(path, body)
.then((response) => response.data);
}
private async delete(path: string): Promise<unknown> {
return this.axiosInstance.delete(path).then((response) => response.data);
}
}
export default new ApiClient();
export type { DonationCreateRequest as CreateDonationRequest };