Appearance
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 editingState Variables
ts
let deviceName: string = ""; // Device name input
let notes: string = ""; // Device notes input
let unsubscribe: { unsubscribe: () => void } | null = null; // Subscription cleanupLifecycle 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
Dual Mode Operation:
- Registration Mode: Shows QR code generation panel
- Edit Mode: Shows only form fields for existing devices
Real-time Updates:
- Subscribes to device addition events via GraphQL
- Notifies parent component when new devices are registered
Form Validation:
- Device name is required
- Input fields have proper validation styling
Responsive Design:
- Adapts layout based on mode (edit vs. register)
- Proper spacing and sizing for all elements
Events
| Event Name | Description | Payload |
|---|---|---|
submit | Form submission | { name: string, notes: string } |
deviceAdded | New device registered notification | Device 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/sveltefor GraphQL operationssvelte-loading-spinnersfor loading animation- Keycloak token management
- Wonka for subscription handling