Livrare Lot 3 (Frontend): aplicație web, aplicație mobilă Android, extensie browser
- Surse complete web (React/Vite) + mobil (React Native/Expo) + extensie (MV3) - Documentație de livrare: ghid utilizare, matrice trasabilitate cerințe, raport testare furnizor - Artefacte binare: imagine Docker didi-frontend:lot3-1.0, APK, extensie v3.2.6 + SHA256SUMS - Configurare adresă platformă externalizată (build args / .env / config.js) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
commit
cec967f953
321 changed files with 80506 additions and 0 deletions
62
android/didi-app-source/src/api/axios.ts
Normal file
62
android/didi-app-source/src/api/axios.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import axios from 'axios';
|
||||
import { Platform } from 'react-native';
|
||||
import { API_CONFIG } from './config';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
|
||||
const USER_AGENT =
|
||||
'Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36 DidiApp/1.0';
|
||||
|
||||
// Browser forbids setting User-Agent — only set on native
|
||||
const nativeHeaders = Platform.OS !== 'web' ? { 'User-Agent': USER_AGENT } : {};
|
||||
|
||||
if (Platform.OS !== 'web') {
|
||||
axios.defaults.headers.common['User-Agent'] = USER_AGENT;
|
||||
}
|
||||
|
||||
export const skillsApi = axios.create({
|
||||
baseURL: API_CONFIG.SKILLS_API,
|
||||
timeout: 300000,
|
||||
headers: nativeHeaders,
|
||||
});
|
||||
|
||||
export const mainApi = axios.create({
|
||||
baseURL: API_CONFIG.MAIN_API,
|
||||
timeout: 30000,
|
||||
headers: nativeHeaders,
|
||||
});
|
||||
|
||||
// Request interceptor - attach token & auto-refresh
|
||||
const attachToken = async (config: any) => {
|
||||
const { accessToken, expiresAt, refreshAccessToken } = useAuthStore.getState();
|
||||
|
||||
if (expiresAt && Date.now() > expiresAt - 30000) {
|
||||
const newToken = await refreshAccessToken();
|
||||
if (newToken) {
|
||||
config.headers.Authorization = `Bearer ${newToken}`;
|
||||
}
|
||||
} else if (accessToken) {
|
||||
config.headers.Authorization = `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
// Response interceptor - retry on 401 (max once to prevent infinite loops)
|
||||
const handle401 = async (error: any) => {
|
||||
const config = error.config;
|
||||
if (error.response?.status === 401 && !config?._retried) {
|
||||
config._retried = true;
|
||||
const newToken = await useAuthStore.getState().refreshAccessToken();
|
||||
if (newToken) {
|
||||
config.headers.Authorization = `Bearer ${newToken}`;
|
||||
return axios.request(config);
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
};
|
||||
|
||||
skillsApi.interceptors.request.use(attachToken);
|
||||
skillsApi.interceptors.response.use((r) => r, handle401);
|
||||
|
||||
mainApi.interceptors.request.use(attachToken);
|
||||
mainApi.interceptors.response.use((r) => r, handle401);
|
||||
Loading…
Add table
Add a link
Reference in a new issue