| |
| |
| |
|
|
| export interface OutbreakLocation { |
| id: string |
| lat: number |
| lng: number |
| crop: string |
| disease: string |
| severity: 'low' | 'medium' | 'high' |
| date: string |
| description: string |
| } |
|
|
| export interface FarmerLocation { |
| id: string |
| name: string |
| email?: string |
| lat: number |
| lng: number |
| crops: string[] |
| radius: number |
| } |
|
|
| export interface Notification { |
| id: string |
| farmerId: string |
| outbreakId: string |
| distance: number |
| message: string |
| severity: 'low' | 'medium' | 'high' |
| read: boolean |
| createdAt: string |
| } |
|
|
| |
| |
| |
| |
| export function calculateDistance( |
| lat1: number, |
| lng1: number, |
| lat2: number, |
| lng2: number |
| ): number { |
| const R = 3959 |
| const dLat = toRad(lat2 - lat1) |
| const dLng = toRad(lng2 - lng1) |
|
|
| const a = |
| Math.sin(dLat / 2) * Math.sin(dLat / 2) + |
| Math.cos(toRad(lat1)) * |
| Math.cos(toRad(lat2)) * |
| Math.sin(dLng / 2) * |
| Math.sin(dLng / 2) |
|
|
| const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) |
| return R * c |
| } |
|
|
| function toRad(degrees: number): number { |
| return (degrees * Math.PI) / 180 |
| } |
|
|
| |
| |
| |
| export function shouldNotifyFarmer( |
| farmer: FarmerLocation, |
| outbreak: OutbreakLocation |
| ): boolean { |
| |
| if (!farmer.crops.includes(outbreak.crop.toLowerCase())) { |
| return false |
| } |
|
|
| |
| const distance = calculateDistance( |
| farmer.lat, |
| farmer.lng, |
| outbreak.lat, |
| outbreak.lng |
| ) |
|
|
| |
| return distance <= farmer.radius |
| } |
|
|
| |
| |
| |
| export function generateNotificationMessage( |
| outbreak: OutbreakLocation, |
| distance: number |
| ): string { |
| return `${outbreak.severity.toUpperCase()} ALERT: ${outbreak.disease} detected in ${outbreak.crop} ${distance.toFixed(1)} miles away` |
| } |
|
|
| |
| |
| |
| export function findAffectedFarmers( |
| outbreak: OutbreakLocation, |
| farmers: FarmerLocation[] |
| ): Array<{ farmer: FarmerLocation; distance: number }> { |
| const affected: Array<{ farmer: FarmerLocation; distance: number }> = [] |
|
|
| for (const farmer of farmers) { |
| if (shouldNotifyFarmer(farmer, outbreak)) { |
| const distance = calculateDistance( |
| farmer.lat, |
| farmer.lng, |
| outbreak.lat, |
| outbreak.lng |
| ) |
| affected.push({ farmer, distance }) |
| } |
| } |
|
|
| |
| return affected.sort((a, b) => a.distance - b.distance) |
| } |
|
|
| |
| |
| |
| export function createNotifications( |
| outbreak: OutbreakLocation, |
| affectedFarmers: Array<{ farmer: FarmerLocation; distance: number }> |
| ): Notification[] { |
| return affectedFarmers.map(({ farmer, distance }) => ({ |
| id: `${outbreak.id}-${farmer.id}-${Date.now()}`, |
| farmerId: farmer.id, |
| outbreakId: outbreak.id, |
| distance, |
| message: generateNotificationMessage(outbreak, distance), |
| severity: outbreak.severity, |
| read: false, |
| createdAt: new Date().toISOString(), |
| })) |
| } |
|
|