104 lines
2.6 KiB
TypeScript
104 lines
2.6 KiB
TypeScript
/**
|
|
* Middleware for handling responsive API requests
|
|
* Ensures backend responds appropriately to different device types
|
|
*/
|
|
|
|
export interface DeviceInfo {
|
|
type: 'mobile' | 'tablet' | 'desktop';
|
|
userAgent: string;
|
|
screenWidth?: number;
|
|
screenHeight?: number;
|
|
}
|
|
|
|
/**
|
|
* Detect device type from User-Agent and viewport
|
|
*/
|
|
export function detectDevice(userAgent: string, width?: number): DeviceInfo['type'] {
|
|
const mobileRegex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
|
|
const tabletRegex = /iPad|Android(?!.*Mobile)/i;
|
|
|
|
if (width) {
|
|
if (width < 768) return 'mobile';
|
|
if (width < 1024) return 'tablet';
|
|
return 'desktop';
|
|
}
|
|
|
|
if (tabletRegex.test(userAgent)) return 'tablet';
|
|
if (mobileRegex.test(userAgent)) return 'mobile';
|
|
return 'desktop';
|
|
}
|
|
|
|
/**
|
|
* Optimize response payload based on device type
|
|
* Reduces data transfer for mobile devices
|
|
*/
|
|
export function optimizePayload<T extends Record<string, any>>(
|
|
data: T,
|
|
deviceType: DeviceInfo['type']
|
|
): T {
|
|
if (deviceType === 'mobile') {
|
|
// Remove heavy fields for mobile
|
|
const optimized = { ...data } as any;
|
|
|
|
// Remove high-res images, use thumbnails instead
|
|
if ('images' in data && Array.isArray(data.images)) {
|
|
optimized.images = (data.images as any[]).map((img: any) => ({
|
|
...img,
|
|
url: img.thumbnail || img.url,
|
|
highRes: undefined,
|
|
}));
|
|
}
|
|
|
|
// Limit array sizes for mobile
|
|
if ('items' in data && Array.isArray(data.items)) {
|
|
optimized.items = (data.items as any[]).slice(0, 10);
|
|
}
|
|
|
|
return optimized;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Add device info to API request headers
|
|
*/
|
|
export function addDeviceHeaders(headers: HeadersInit = {}): HeadersInit {
|
|
const width = typeof window !== 'undefined' ? window.innerWidth : undefined;
|
|
const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : '';
|
|
const deviceType = detectDevice(userAgent, width);
|
|
|
|
return {
|
|
...headers,
|
|
'X-Device-Type': deviceType,
|
|
'X-Screen-Width': width?.toString() || '',
|
|
'X-User-Agent': userAgent,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Adaptive pagination based on device
|
|
*/
|
|
export function getAdaptivePagination(deviceType: DeviceInfo['type']) {
|
|
const limits = {
|
|
mobile: 10,
|
|
tablet: 20,
|
|
desktop: 50,
|
|
};
|
|
|
|
return {
|
|
limit: limits[deviceType],
|
|
offset: 0,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Image quality based on device and connection
|
|
*/
|
|
export function getImageQuality(deviceType: DeviceInfo['type'], connectionType?: string): number {
|
|
if (connectionType === 'slow-2g' || connectionType === '2g') return 30;
|
|
if (deviceType === 'mobile') return 60;
|
|
if (deviceType === 'tablet') return 80;
|
|
return 90;
|
|
}
|