refactor(all): migrate from React to Next.js

This commit is contained in:
2026-05-20 09:46:17 +03:30
parent dacbd3a328
commit f23108cda3
86 changed files with 2831 additions and 2679 deletions

View File

@@ -1,7 +1,8 @@
import type * as Types from './types';
import { apiBaseUrl } from '@/lib/site';
const API_BASE_URL =
import.meta.env.VITE_API_BASE_URL?.replace(/\/$/, '') || 'https://api.east-guilan-ce.ir';
apiBaseUrl;
type ApiErrorBody = {
error?: string;
@@ -18,8 +19,32 @@ class ApiClient {
this.baseUrl = baseUrl;
}
private getStorageValue(key: string) {
if (typeof window === 'undefined') {
return null;
}
return window.localStorage.getItem(key);
}
private setStorageValue(key: string, value: string) {
if (typeof window === 'undefined') {
return;
}
window.localStorage.setItem(key, value);
}
private removeStorageValue(key: string) {
if (typeof window === 'undefined') {
return;
}
window.localStorage.removeItem(key);
}
private getAuthHeaders(): HeadersInit {
const token = localStorage.getItem('access_token');
const token = this.getStorageValue('access_token');
return {
'Content-Type': 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
@@ -27,7 +52,7 @@ class ApiClient {
}
private async refreshAccessToken(): Promise<string> {
const refreshToken = localStorage.getItem('refresh_token');
const refreshToken = this.getStorageValue('refresh_token');
if (!refreshToken) {
throw new Error('No refresh token available');
}
@@ -39,14 +64,14 @@ class ApiClient {
});
if (!response.ok) {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
this.removeStorageValue('access_token');
this.removeStorageValue('refresh_token');
throw new Error('Session expired. Please login again.');
}
const data: Types.TokenSchema = await response.json();
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('refresh_token', data.refresh_token);
this.setStorageValue('access_token', data.access_token);
this.setStorageValue('refresh_token', data.refresh_token);
return data.access_token;
}
@@ -75,7 +100,7 @@ class ApiClient {
const response = await fetch(url, config);
// Handle 401 with automatic token refresh
if (response.status === 401 && localStorage.getItem('refresh_token')) {
if (response.status === 401 && this.getStorageValue('refresh_token')) {
if (!this.isRefreshing) {
this.isRefreshing = true;
try {
@@ -184,7 +209,6 @@ class ApiClient {
}
async getProfile() {
const token = localStorage.getItem('access_token');
return this.request<Types.UserProfileSchema>('/api/auth/profile'
);
}
@@ -200,7 +224,7 @@ class ApiClient {
const formData = new FormData();
formData.append('file', file);
const token = localStorage.getItem('access_token');
const token = this.getStorageValue('access_token');
const response = await fetch(`${this.baseUrl}/api/auth/profile/picture`, {
method: 'POST',
headers: {
@@ -469,7 +493,7 @@ class ApiClient {
}
async updateEvent(eventId: number, data: Types.EventUpdateSchema) {
return this.request<Types.EventSchema>(`/api/events/${eventId}`, {
return this.request<Types.EventDetailSchema>(`/api/events/${eventId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
@@ -614,7 +638,7 @@ class ApiClient {
if (data.description) formData.append('description', data.description);
if (data.tag_ids) formData.append('tag_ids', JSON.stringify(data.tag_ids));
const token = localStorage.getItem('access_token');
const token = this.getStorageValue('access_token');
const response = await fetch(`${this.baseUrl}/api/gallery/images`, {
method: 'POST',
headers: {