# Angular Mobile App - Geofence Check-In Integration Guide

## Quick Reference - API Responses & Error Handling

---

## 1. Get Employee Profile (Load Assigned Locations)

### Endpoint
```
GET /api/v1/employee/profile
```

### Response
```json
{
  "success": true,
  "data": {
    "assigned_locations": [
      {
        "id": 1,
        "service": {
          "id": 1,
          "name": "Security Patrol - Building A",
          "zone_area": "North Wing"
        },
        "location": {
          "id": 1,
          "name": "Main Office",
          "address": "123 Main St, Bangalore - 560001",
          "city": "Bangalore",
          "latitude": 12.9716,
          "longitude": 77.5946
        },
        "is_active": true
      }
    ],
    "assigned_locations_count": 1
  }
}
```

### Usage in Component
```typescript
export class CheckInComponent implements OnInit {
  assignedLocations: any[] = [];
  employeeProfile: any;

  ngOnInit() {
    this.loadProfile();
  }

  loadProfile() {
    this.employeeService.getProfile().subscribe(
      (response) => {
        this.employeeProfile = response.data;
        this.assignedLocations = response.data.assigned_locations;
        
        // Display locations on map
        this.displayLocationsOnMap();
      },
      (error) => {
        console.error('Failed to load profile', error);
      }
    );
  }

  displayLocationsOnMap() {
    this.assignedLocations.forEach(location => {
      if (location.location?.latitude && location.location?.longitude) {
        this.map.addMarker({
          lat: location.location.latitude,
          lng: location.location.longitude,
          title: location.location.name,
          infoWindow: {
            title: location.location.name,
            content: location.location.address
          }
        });
      }
    });
  }
}
```

---

## 2. Check-In with Geofence Validation

### Endpoint
```
POST /api/v1/attendance/clock-in
```

### Request
```json
{
  "latitude": 12.9716,
  "longitude": 77.5946,
  "remarks": "Office check-in",
  "accuracy": 25
}
```

### Success Response (200/201)
```json
{
  "success": true,
  "message": "Clocked in successfully",
  "data": {
    "attendance_id": 123,
    "punch_time": "2026-07-01T12:20:00Z",
    "behavior": "regular"
  }
}
```

### Error Response (400) - Not in Geofence
```json
{
  "success": false,
  "message": "You are not within any authorized geofence. Please move to your assigned location to clock in.",
  "data": {
    "current_location": {
      "latitude": 12.997422,
      "longitude": 80.211936,
      "accuracy_meters": 25
    },
    "assigned_geofences": [
      {
        "name": "Building A - Security Gate",
        "location": "Main Office, Bangalore",
        "address": "123 Main St, Bangalore - 560001",
        "coordinates": {
          "latitude": 12.9716,
          "longitude": 77.5946
        },
        "distance_meters": 3245
      },
      {
        "name": "Building B - Entrance",
        "location": "Secondary Office, Bangalore",
        "address": "456 Secondary St, Bangalore - 560002",
        "coordinates": {
          "latitude": 12.9745,
          "longitude": 77.5976
        },
        "distance_meters": 4120
      }
    ],
    "help_message": "Your assigned locations are: Main Office; Secondary Office",
    "nearby_geofences": []
  }
}
```

### Angular Error Handling
```typescript
export class CheckInComponent {
  checkIn() {
    this.location.getLocation()
      .then((position) => {
        this.attendanceService.clockIn({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          remarks: this.remarks
        }).subscribe(
          (response) => {
            this.showSuccessAlert('Clocked in successfully!');
            this.navigateToHome();
          },
          (error) => {
            if (error.status === 400) {
              // Geofence error - show navigation UI
              this.handleGeofenceError(error.error.data);
            } else {
              this.showErrorAlert(error.error.message);
            }
          }
        );
      })
      .catch((error) => {
        console.error('Location error', error);
        this.showErrorAlert('Unable to get your location. Please enable location services.');
      });
  }

  handleGeofenceError(data: any) {
    const { assigned_geofences, current_location, help_message } = data;
    
    // Show modal with location options
    this.showGeofenceModal({
      title: 'Location Required',
      message: help_message,
      currentLocation: current_location,
      locations: assigned_geofences,
      onNavigate: (location) => {
        this.openMapsNavigation(location.coordinates);
      }
    });
  }

  openMapsNavigation(coordinates: { latitude: number; longitude: number }) {
    // Open Google Maps or Apple Maps with navigation
    const url = `https://maps.google.com/?q=${coordinates.latitude},${coordinates.longitude}`;
    window.open(url, '_blank');
  }
}
```

---

## 3. Get Geofence Details

### Endpoint
```
GET /api/v1/employee/geofence
```

### Response
```json
{
  "success": true,
  "data": {
    "geofences": [
      {
        "id": 1,
        "name": "Building A - Perimeter",
        "type": "radius",
        "service": {
          "id": 1,
          "name": "Security Patrol",
          "zone_area": "North Wing"
        },
        "location": {
          "id": 1,
          "name": "Main Office",
          "address": "123 Main St",
          "city": "Bangalore",
          "latitude": 12.9716,
          "longitude": 77.5946
        },
        "geometry": {
          "type": "radius",
          "radius": 100,
          "coordinates": { "lat": 12.9716, "lng": 77.5946 },
          "tolerance": 50
        },
        "is_active": true
      }
    ],
    "summary": {
      "total_geofences": 1,
      "active_geofences": 1,
      "circular_geofences": 1
    }
  }
}
```

### Usage for Map Display
```typescript
export class GeofenceMapComponent implements OnInit {
  geofences: any[] = [];
  map: any;

  ngOnInit() {
    this.loadGeofences();
  }

  loadGeofences() {
    this.geofencingService.getGeofences().subscribe(
      (response) => {
        this.geofences = response.data.geofences;
        this.drawGeofencesOnMap();
      }
    );
  }

  drawGeofencesOnMap() {
    this.geofences.forEach(geofence => {
      switch (geofence.geometry.type) {
        case 'radius':
        case 'circular':
          this.drawCircle(geofence);
          break;
        case 'polygon':
          this.drawPolygon(geofence);
          break;
        case 'rectangle':
          this.drawRectangle(geofence);
          break;
      }
    });
  }

  drawCircle(geofence: any) {
    const { coordinates, radius } = geofence.geometry;
    this.map.addCircle({
      center: coordinates,
      radius: radius,
      fillColor: '#4285F4',
      strokeColor: '#4285F4',
      strokeOpacity: 0.8,
      infoWindow: {
        title: geofence.name,
        content: geofence.location.address
      }
    });
  }
}
```

---

## 4. Check Geofence Status

### Endpoint
```
POST /api/v1/employee/geofence/check
```

### Request
```json
{
  "latitude": 12.9716,
  "longitude": 77.5946,
  "accuracy": 25
}
```

### Response - Inside Geofence
```json
{
  "success": true,
  "data": {
    "inside_any": true,
    "inside_geofences": [
      {
        "geofence_id": 1,
        "name": "Building A - Perimeter",
        "service": { "name": "Security Patrol" },
        "location": {
          "name": "Main Office",
          "latitude": 12.9716,
          "longitude": 77.5946
        },
        "distance_from_center": 45.2
      }
    ],
    "all_assigned_geofences": [...]
  }
}
```

### Response - Outside Geofence
```json
{
  "success": true,
  "data": {
    "inside_any": false,
    "inside_geofences": [],
    "all_assigned_geofences": [
      {
        "geofence_id": 1,
        "name": "Building A - Perimeter",
        "location": { "latitude": 12.9716, "longitude": 77.5946 },
        "distance_from_center": 3245.5
      }
    ],
    "current_position": {
      "latitude": 12.997422,
      "longitude": 80.211936,
      "accuracy": 25
    }
  }
}
```

### Real-time Status Monitoring
```typescript
export class RealtimeGeofenceComponent {
  geofenceStatus: any;
  
  startMonitoring() {
    // Check status every 10 seconds
    setInterval(() => {
      this.location.getLocation()
        .then((position) => {
          this.geofencingService.checkGeofence({
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
            accuracy: position.coords.accuracy
          }).subscribe(
            (response) => {
              this.geofenceStatus = response.data;
              this.updateUI();
            }
          );
        });
    }, 10000);
  }

  updateUI() {
    if (this.geofenceStatus.inside_any) {
      this.setStatus('INSIDE GEOFENCE - Ready to check in', 'success');
    } else {
      const nearest = this.findNearestGeofence();
      this.setStatus(
        `OUTSIDE GEOFENCE - ${nearest.distance_from_center}m to ${nearest.name}`,
        'warning'
      );
    }
  }

  findNearestGeofence() {
    return this.geofenceStatus.all_assigned_geofences
      .reduce((min, g) => g.distance_from_center < min.distance_from_center ? g : min);
  }
}
```

---

## 5. Error Modal Component

### Template
```html
<ion-modal [isOpen]="showGeofenceModal">
  <ng-template>
    <ion-content>
      <ion-header>
        <ion-toolbar color="danger">
          <ion-title>Location Required</ion-title>
          <ion-buttons slot="end">
            <ion-button (click)="dismiss()">✕</ion-button>
          </ion-buttons>
        </ion-toolbar>
      </ion-header>

      <ion-card>
        <ion-card-header>
          <ion-card-title>Current Location</ion-card-title>
        </ion-card-header>
        <ion-card-content>
          <p><strong>Latitude:</strong> {{ currentLocation.latitude }}</p>
          <p><strong>Longitude:</strong> {{ currentLocation.longitude }}</p>
          <p><strong>Accuracy:</strong> {{ currentLocation.accuracy_meters }}m</p>
        </ion-card-content>
      </ion-card>

      <ion-card>
        <ion-card-header>
          <ion-card-title>Assigned Locations</ion-card-title>
          <ion-card-subtitle>{{ helpMessage }}</ion-card-subtitle>
        </ion-card-header>
        <ion-card-content>
          <ion-list>
            <ion-item *ngFor="let location of assignedGeofences">
              <ion-label>
                <h2><strong>{{ location.name }}</strong></h2>
                <p>{{ location.address }}</p>
                <p class="distance">{{ location.distance_meters }}m away</p>
              </ion-label>
              <ion-button 
                slot="end" 
                fill="solid" 
                color="primary"
                (click)="navigateTo(location.coordinates)">
                Navigate
              </ion-button>
            </ion-item>
          </ion-list>
        </ion-card-content>
      </ion-card>
    </ion-content>
  </ng-template>
</ion-modal>
```

### Component
```typescript
@Component({
  selector: 'app-geofence-error',
  templateUrl: './geofence-error.modal.html'
})
export class GeofenceErrorModalComponent {
  @Input() currentLocation: any;
  @Input() assignedGeofences: any[];
  @Input() helpMessage: string;

  constructor(private launchNavigator: LaunchNavigator) {}

  navigateTo(coordinates: { latitude: number; longitude: number }) {
    const destination = `${coordinates.latitude},${coordinates.longitude}`;
    this.launchNavigator.navigate(destination, {
      type: this.launchNavigator.LAUNCH_MODE.URI_SCHEME,
    });
  }
}
```

---

## Distance Calculation (Frontend)

```typescript
calculateDistance(
  lat1: number, 
  lon1: number, 
  lat2: number, 
  lon2: number
): number {
  const R = 6371000; // Earth radius in meters
  const dLat = this.toRad(lat2 - lat1);
  const dLon = this.toRad(lon2 - lon1);
  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(this.toRad(lat1)) *
      Math.cos(this.toRad(lat2)) *
      Math.sin(dLon / 2) *
      Math.sin(dLon / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  return R * c; // Distance in meters
}

toRad(deg: number): number {
  return deg * (Math.PI / 180);
}
```

---

## Best Practices

1. **Always get location before check-in**
   - Use device's GPS for accuracy
   - Request high accuracy mode
   - Handle location errors gracefully

2. **Handle network errors**
   - Retry geofence check if network fails
   - Show offline mode warning
   - Queue check-in for retry

3. **Update location periodically**
   - Poll every 10 seconds while on check-in screen
   - Show real-time distance to geofence
   - Update UI based on geofence status

4. **Provide clear navigation**
   - Show nearest location
   - Open maps on tap
   - Display address and distance clearly

5. **Permission handling**
   - Request GPS permission on app startup
   - Show permission denied alert
   - Provide link to settings

---

## Common Issues & Solutions

### Issue: Geofence check always returns "not inside"
**Solution**: Verify:
- GPS is enabled on device
- Location accuracy is > 30m
- Geofence coordinates are correct
- Employee is actually within radius

### Issue: Distance showing as NaN
**Solution**: Check:
- Coordinates are valid numbers
- Not null or undefined
- Using correct Haversine formula
- Latitude range: -90 to 90
- Longitude range: -180 to 180

### Issue: Map markers not showing
**Solution**: Verify:
- Location has latitude/longitude
- Map has correct center coordinates
- Map library is properly initialized
- Permissions are granted

---

## Testing Coordinates

### Test Locations (Bangalore)
```typescript
// Main Office
const mainOffice = {
  latitude: 12.9716,
  longitude: 77.5946
};

// Secondary Office
const secondaryOffice = {
  latitude: 12.9745,
  longitude: 77.5976
};

// Test point outside
const outside = {
  latitude: 12.997422,
  longitude: 80.211936
};
```

---

## References

- [Geofence API Documentation](/docs/Geofencing_API.md)
- [Employee Check-In Flow](/docs/EMPLOYEE_SERVICE_TRANSIT_API.md)
- [Hierarchical Access](/docs/Hierarchical_Access_Implementation.md)
