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:
Top Clossers 2026-07-17 12:33:59 +03:00
commit cec967f953
321 changed files with 80506 additions and 0 deletions

View 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);