Skip to content

Device Registration Form Component Documentation

File: src/pages/private/admin/devices/form.svelte

Overview

This component provides a form interface for registering and editing Headset devices, with support for QR code generation and real-time subscription to device addition events.

Module Script (GraphQL Subscriptions)

ts
export const DEVICE_ADDED_SUBSCRIPTION = gql`
  subscription devicedAdded($token: String!) {
    onDeviceAdded(token: $token) {
      deviceRefToken
    }
  }
`;

export const ACTIVE_DEVICE_CHANGED = gql`
  subscription activeDeviceChanged {
    onActiveDeviceChanged {
      connected, refId
    }
  }
`;

Component Script

Props

ts
export let qrCodeUrl: string = ""; // URL for generated QR code
export let loading: boolean = false; // Loading state
export let edit: boolean = false; // Edit mode flag
export let data: any = null; // Existing device data for editing

State Variables

ts
let deviceName: string = ""; // Device name input
let notes: string = ""; // Device notes input
let unsubscribe: { unsubscribe: () => void } | null = null; // Subscription cleanup

Lifecycle Methods

ts
onMount(() => {
  // Initialize form with existing data if in edit mode
  if (data) {
    deviceName = data.name || "";
    notes = data.notes || "";
  }

  // Subscribe to device addition events
  const client = getClient();
  const token = get(accessToken);
  const subscription$ = client.subscription(DEVICE_ADDED_SUBSCRIPTION, { token });
  
  unsubscribe = subscribe((result) => {
    if (result.data?.onDeviceAdded?.deviceRefToken) {
      dispatch("deviceAdded", result.data.onDeviceAdded.deviceRefToken);
    }
  })(subscription$);
});

onDestroy(() => {
  // Clean up subscription
  if (unsubscribe?.unsubscribe) {
    unsubscribe.unsubscribe();
  }
});

Event Handlers

ts
function handleSubmit() {
  dispatch("submit", { name: deviceName, notes });
}

UI Structure

Form Layout

svelte
<div class="p-6 w-full">
  <form on:submit|preventDefault={handleSubmit} class="flex gap-4 w-full">
    <!-- Left Column: Form Inputs -->
    <div class="flex flex-col gap-4 w-full">
      <!-- Device Name Input -->
      <div>
        <label for="deviceName">Device Name</label>
        <input
          id="deviceName"
          type="text"
          bind:value={deviceName}
          required
        />
      </div>
      
      <!-- Notes Textarea -->
      <div>
        <label for="notes">Notes</label>
        <textarea
          id="notes"
          bind:value={notes}
          rows={8}
        ></textarea>
      </div>
      
      <!-- Edit Mode Submit Button -->
      {#if edit}
        {#if loading}
          <div class="w-full mt-4 flex justify-center py-2">
            <Chasing />
          </div>
        {:else}
          <button type="submit">Update Device</button>
        {/if}
      {/if}
    </div>
    
    <!-- Right Column: QR Code (Non-Edit Mode Only) -->
    {#if !edit}
      <div class="w-[700px]">
        <label for="qrCode">QR Code</label>
        <div class="flex flex-col items-center space-y-2 p-4 border-2 border-dashed border-gray-300 rounded-md">
          {#if loading}
            <div class="flex-grow grid place-content-center my-3 py-3 h-[175px]">
              <Chasing />
            </div>
          {:else if qrCodeUrl}
            <img src={qrCodeUrl} alt="Device QR Code" />
          {:else}
            <div class="text-center p-8">
              <!-- Placeholder SVG -->
              <p class="mt-2 text-sm text-gray-500">QR Code</p>
            </div>
          {/if}
        </div>
        <button type="submit">Generate</button>
      </div>
    {/if}
  </form>
</div>

Key Features

  1. Dual Mode Operation:

    • Registration Mode: Shows QR code generation panel
    • Edit Mode: Shows only form fields for existing devices
  2. Real-time Updates:

    • Subscribes to device addition events via GraphQL
    • Notifies parent component when new devices are registered
  3. Form Validation:

    • Device name is required
    • Input fields have proper validation styling
  4. Responsive Design:

    • Adapts layout based on mode (edit vs. register)
    • Proper spacing and sizing for all elements

Events

Event NameDescriptionPayload
submitForm submission{ name: string, notes: string }
deviceAddedNew device registered notificationDevice reference token

Usage Example

svelte
<script>
  import Form from "./form.svelte";
  
  let qrCode = "";
  let loading = false;
  
  function handleSubmit({ detail }) {
    // Call API to generate QR code
    loading = true;
    generateDeviceQR(detail.name, detail.notes)
      .then(url => qrCode = url)
      .finally(() => loading = false);
  }
  
  function handleDeviceAdded(token) {
    console.log("Device registered:", token);
  }
</script>

<Form 
  bind:qrCodeUrl={qrCode} 
  bind:loading 
  on:submit={handleSubmit}
  on:deviceAdded={handleDeviceAdded}
/>

Styling

  • Input Fields: Consistent styling with focus states
  • QR Code Area: Dashed border placeholder
  • Buttons: Primary action styling with hover states
  • Loading States: Centered spinners during operations

Dependencies

  • @urql/svelte for GraphQL operations
  • svelte-loading-spinners for loading animation
  • Keycloak token management
  • Wonka for subscription handling

Released under the MIT License.