Restructure with Turborepo
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import axios from 'axios';
|
||||
import * as SecureStore from 'expo-secure-store';
|
||||
import { config } from '../constants/config';
|
||||
|
||||
export const api = axios.create({
|
||||
baseURL: config.API_BASE_URL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Request interceptor - add auth token
|
||||
api.interceptors.request.use(
|
||||
async (axiosConfig) => {
|
||||
const token = await SecureStore.getItemAsync('auth_token');
|
||||
if (token) {
|
||||
axiosConfig.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return axiosConfig;
|
||||
},
|
||||
(error) => Promise.reject(error)
|
||||
);
|
||||
|
||||
// Response interceptor - handle errors
|
||||
api.interceptors.response.use(
|
||||
(response) => response,
|
||||
async (error) => {
|
||||
if (error.response?.status === 401) {
|
||||
await SecureStore.deleteItemAsync('auth_token');
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default api;
|
||||
@@ -0,0 +1,43 @@
|
||||
import api from './api';
|
||||
import * as SecureStore from 'expo-secure-store';
|
||||
import { AuthResponse, User } from '../types';
|
||||
|
||||
export async function login(username: string, password: string): Promise<AuthResponse> {
|
||||
const response = await api.post('/auth/login', { username, password });
|
||||
const { user, token } = response.data;
|
||||
|
||||
await SecureStore.setItemAsync('auth_token', token);
|
||||
await SecureStore.setItemAsync('user', JSON.stringify(user));
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function logout(): Promise<void> {
|
||||
await api.post('/auth/logout');
|
||||
await SecureStore.deleteItemAsync('auth_token');
|
||||
await SecureStore.deleteItemAsync('user');
|
||||
}
|
||||
|
||||
export async function checkAuth(): Promise<User | null> {
|
||||
try {
|
||||
const response = await api.get('/auth/check');
|
||||
return response.data.user;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStoredUser(): Promise<User | null> {
|
||||
const userStr = await SecureStore.getItemAsync('user');
|
||||
return userStr ? JSON.parse(userStr) : null;
|
||||
}
|
||||
|
||||
export async function register(username: string, password: string): Promise<AuthResponse> {
|
||||
const response = await api.post('/auth/register', { username, password });
|
||||
const { user, token } = response.data;
|
||||
|
||||
await SecureStore.setItemAsync('auth_token', token);
|
||||
await SecureStore.setItemAsync('user', JSON.stringify(user));
|
||||
|
||||
return response.data;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import * as LocalAuthentication from 'expo-local-authentication';
|
||||
import * as SecureStore from 'expo-secure-store';
|
||||
|
||||
export async function isBiometricsAvailable(): Promise<boolean> {
|
||||
const compatible = await LocalAuthentication.hasHardwareAsync();
|
||||
const enrolled = await LocalAuthentication.isEnrolledAsync();
|
||||
return compatible && enrolled;
|
||||
}
|
||||
|
||||
export async function authenticateWithBiometrics(): Promise<boolean> {
|
||||
try {
|
||||
const result = await LocalAuthentication.authenticateAsync({
|
||||
promptMessage: 'Inicia sesión con biometría',
|
||||
cancelLabel: 'Cancelar',
|
||||
disableDeviceFallback: false,
|
||||
});
|
||||
return result.success;
|
||||
} catch (error) {
|
||||
console.error('Biometric authentication error:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveBiometricCredentials(username: string): Promise<void> {
|
||||
await SecureStore.setItemAsync('biometric_username', username);
|
||||
}
|
||||
|
||||
export async function getBiometricUsername(): Promise<string | null> {
|
||||
return await SecureStore.getItemAsync('biometric_username');
|
||||
}
|
||||
|
||||
export async function clearBiometricCredentials(): Promise<void> {
|
||||
await SecureStore.deleteItemAsync('biometric_username');
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import api from './api';
|
||||
import { Medicine, PharmacyMedicine } from '../types';
|
||||
|
||||
export async function searchMedicines(query: string): Promise<Medicine[]> {
|
||||
const response = await api.get(`/medicines/search?q=${encodeURIComponent(query)}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function getMedicine(nregistro: string): Promise<Medicine> {
|
||||
const response = await api.get(`/medicines/${nregistro}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function getMedicinePharmacies(nregistro: string): Promise<PharmacyMedicine[]> {
|
||||
const response = await api.get(`/medicines/${nregistro}/pharmacies`);
|
||||
return response.data;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import * as Device from 'expo-device';
|
||||
import * as Constants from 'expo-constants';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldShowBanner: true,
|
||||
shouldShowList: true,
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: true,
|
||||
}),
|
||||
});
|
||||
|
||||
export async function registerForPushNotifications() {
|
||||
if (!Device.isDevice) {
|
||||
console.log('Push notifications require a physical device');
|
||||
return null;
|
||||
}
|
||||
|
||||
const { status: existingStatus } = await Notifications.getPermissionsAsync();
|
||||
let finalStatus = existingStatus;
|
||||
|
||||
if (existingStatus !== 'granted') {
|
||||
const { status } = await Notifications.requestPermissionsAsync();
|
||||
finalStatus = status;
|
||||
}
|
||||
|
||||
if (finalStatus !== 'granted') {
|
||||
console.log('Failed to get push token for push notification');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
await Notifications.setNotificationChannelAsync('default', {
|
||||
name: 'default',
|
||||
importance: Notifications.AndroidImportance.MAX,
|
||||
vibrationPattern: [0, 250, 250, 250],
|
||||
lightColor: '#007AFF',
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const projectId =
|
||||
Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId;
|
||||
|
||||
const token = await Notifications.getExpoPushTokenAsync({
|
||||
projectId,
|
||||
});
|
||||
|
||||
return token.data;
|
||||
} catch (e) {
|
||||
console.log('Error getting push token:', e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function scheduleMedicineAvailabilityNotification(
|
||||
medicineName: string,
|
||||
pharmacyName: string
|
||||
) {
|
||||
await Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title: 'Medicamento disponible',
|
||||
body: `${medicineName} está disponible en ${pharmacyName}`,
|
||||
data: { type: 'medicine_availability' },
|
||||
},
|
||||
trigger: null,
|
||||
});
|
||||
}
|
||||
|
||||
export function addNotificationListener(
|
||||
handler: (notification: Notifications.Notification) => void
|
||||
): Notifications.EventSubscription {
|
||||
return Notifications.addNotificationReceivedListener(handler);
|
||||
}
|
||||
|
||||
export function addNotificationResponseListener(
|
||||
handler: (response: Notifications.NotificationResponse) => void
|
||||
): Notifications.EventSubscription {
|
||||
return Notifications.addNotificationResponseReceivedListener(handler);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import api from './api';
|
||||
import { Pharmacy } from '../types';
|
||||
|
||||
export async function getPharmacies(): Promise<Pharmacy[]> {
|
||||
const response = await api.get('/pharmacies');
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function getPharmacy(id: number): Promise<Pharmacy> {
|
||||
const response = await api.get(`/pharmacies/${id}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function getPharmacyMedicines(id: number): Promise<any[]> {
|
||||
const response = await api.get(`/pharmacies/${id}/medicines`);
|
||||
return response.data;
|
||||
}
|
||||
Reference in New Issue
Block a user