Skip to main content
The Incidents App provides a comprehensive incident tracking system that allows guests to report issues and staff to manage and resolve them efficiently.

Overview

The incident tracking system manages the complete lifecycle of incidents from creation to resolution, with real-time status updates and role-based task assignment.

Incident Lifecycle

1

Incident Creation

Guests create incidents through the CreateIncidentForm component, providing:
  • Title: Brief description of the issue
  • Description: Detailed explanation
  • Priority: Low (baja), Medium (media), or High (alta)
  • Area: The responsible department
2

Task Assignment

Incidents appear in the area’s inbox as pending tasks. Staff members can accept tasks from the general inbox.
3

Progress Tracking

Once accepted, the incident moves through status stages:
  • pendiente (Pending)
  • recibida (Received)
  • en_progreso (In Progress)
  • resuelta (Resolved)
4

Resolution

Staff members resolve incidents by providing a resolution description and optional evidence photos.

Creating Incidents

The CreateIncidentForm component handles incident creation with form validation and area selection:
CreateIncidentForm.tsx
const handleSubmit = async () => {
  if (!title.trim() || !description.trim() || !priority || !areaId) {
    Alert.alert("Error", "Completa todos los campos");
    return;
  }

  const raw = await SecureStore.getItemAsync("guest_session");
  if (!raw) throw new Error("No hay sesión de huésped");

  const guestSession = JSON.parse(raw);

  const { error } = await supabase.from("incidents").insert({
    title,
    description,
    priority,
    area_id: areaId,
    room_id: guestSession.room_id,
  });

  if (error) throw error;

  Alert.alert("Listo", "Incidencia enviada");
};
Incidents are automatically linked to the guest’s room via the guest_session stored in secure storage.

Priority Levels

Incidents support three priority levels with visual indicators:

Low Priority

Non-urgent issues that can be addressed during regular maintenance

Medium Priority

Issues requiring attention within the same day

High Priority

Urgent issues requiring immediate attention
Priority Configuration
const priorityOptions = [
  { value: "baja", label: "Baja", color: "#10B981", bgColor: "#ECFDF5" },
  { value: "media", label: "Media", color: "#F59E0B", bgColor: "#FEF3C7" },
  { value: "alta", label: "Alta", color: "#EF4444", bgColor: "#FEE2E2" },
];

Viewing Incidents

Guest View

Guests can view their submitted incidents through the MyIncidentsView component:
MyIncidentsView.tsx
const loadIncidents = async () => {
  const raw = await SecureStore.getItemAsync("guest_session");
  const guestSession = JSON.parse(raw);

  const { data, error } = await supabase
    .from("incidents")
    .select(
      "id, title, description, priority, status, created_at, areas(name)"
    )
    .eq("room_id", guestSession.room_id)
    .order("created_at", { ascending: false });

  setIncidents((data || []) as unknown as Incident[]);
};

Staff View

Staff members see incidents in two views:
Shows incidents assigned to the logged-in employee:
EmpleadoMyTasks.tsx
const { data, error } = await supabase
  .from("incidents")
  .select(
    "id, title, description, priority, status, created_at, areas(name)"
  )
  .eq("assigned_to", user.id)
  .order("created_at", { ascending: false });
Shows all pending incidents for the employee’s area:
EmpleadoBuzonIncidents.tsx
const { data, error } = await supabase
  .from("incidents")
  .select(
    "id, title, description, priority, status, created_at, areas(name), rooms(room_code)"
  )
  .eq("status", "pendiente")
  .eq("area_id", areaData.id)
  .order("created_at", { ascending: false });

Incident Card Component

The IncidentCard component displays incident information with visual status indicators:
IncidentCard.tsx
const statusConfig: Record<string, { label: string; color: string; textColor: string }> = {
  pendiente: { label: "Pendiente", color: "#6b72801c", textColor: "#6b7280da" },
  recibida: { label: "Recibida", color: "#FEF3C7", textColor: "#F59E0B" },
  en_progreso: {
    label: "En Progreso",
    color: "#3b83f61a",
    textColor: "#3b83f6cd",
  },
  resuelta: { label: "Resuelta", color: "#10b98119", textColor: "#10b981c3" },
};
The card component is reusable across both guest and staff interfaces with different interaction behaviors.

Task Management

Accepting Tasks

Staff members can accept tasks from the general inbox:
incidents/[id].tsx
const handleAcceptTask = async () => {
  // Verify task is still pending
  const { data: currentIncident } = await supabase
    .from("incidents")
    .select("status")
    .eq("id", id)
    .single();

  if (currentIncident.status !== "pendiente") {
    Alert.alert(
      "Tarea no disponible",
      "Esta tarea ya fue aceptada por otro empleado del área."
    );
    return;
  }

  // Accept the task
  const { error } = await supabase
    .from("incidents")
    .update({
      status: "recibida",
      assigned_to: currentUserId,
    })
    .eq("id", id);
};

Updating Status

Once received, staff can update the status to “in progress” by tapping the status badge:
const handleStatusClick = async () => {
  if (incident?.status !== "recibida" || !isAssignedToMe) return;

  const { error } = await supabase
    .from("incidents")
    .update({
      status: "en_progreso",
      updated_at: new Date().toISOString(),
    })
    .eq("id", id);
};

Rejecting Tasks

Staff can reject tasks to return them to the general inbox:
const handleRejectTask = async () => {
  const { error } = await supabase
    .from("incidents")
    .update({
      status: "pendiente",
      assigned_to: null,
    })
    .eq("id", id);
};

Database Schema

The incidents table structure:
CREATE TABLE incidents (
  id UUID PRIMARY KEY,
  title TEXT NOT NULL,
  description TEXT NOT NULL,
  priority TEXT CHECK (priority IN ('baja', 'media', 'alta')),
  status TEXT CHECK (status IN ('pendiente', 'recibida', 'en_progreso', 'resuelta')),
  area_id UUID REFERENCES areas(id),
  room_id UUID REFERENCES rooms(id),
  assigned_to UUID REFERENCES profiles(id),
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

Role-Based Access

Learn about role-based access control

Real-Time Updates

See how incidents update in real-time

Push Notifications

Get notified about incident updates

QR Code Scanning

Learn about guest authentication

Build docs developers (and LLMs) love