Skip to main content

Page Settings System - User Guide

Overview

The page settings system allows you to save and restore user preferences per page, such as:

  • Column count in grid views (2, 3, or 4 columns)
  • View mode (grid vs table)
  • Items per page
  • Any other page-specific UI state

Settings are:

  • User-specific - Each user has their own settings
  • Page-specific - Different pages have independent settings
  • Persistent - Saved in localStorage across browser sessions
  • Automatic - No backend changes needed

Quick Start

1. Import the Hook and Store

import { usePageStore } from "@lib/pageStore"
import { useUserAuth } from "@contexts/UserAuthProvider"
import { usePathname } from "next/navigation"

2. Get User ID and Pathname

const { user } = useUserAuth()
const pathname = usePathname() || ""
const { savePageSettings, getPageSettings } = usePageStore()

const userId = user?.id || "guest"

3. Load Settings on Mount

const [columns, setColumns] = useState<2 | 3 | 4>(() => {
// Load from localStorage on initial render
const saved = usePageStore.getState().getPageSettings(userId, pathname)
return (saved?.columns as 2 | 3 | 4) || 4 // Default to 4
})

4. Save Settings When Changed

const handleColumnsChange = (newColumns: number) => {
setColumns(newColumns as 2 | 3 | 4)

// Save to localStorage
savePageSettings(userId, pathname, {
columns: newColumns as 2 | 3 | 4,
})
}

5. Pass to GridBlock

<GridBlock
columns={columns}
onColumnsChange={handleColumnsChange}
// ... other props
>

Complete Example: Contacts Page

Here's how to add persistent column settings to the contacts page:

"use client"

import { useState, useEffect } from "react"
import { useUserAuth } from "@contexts/UserAuthProvider"
import { usePathname } from "next/navigation"
import { usePageStore } from "@lib/pageStore"
import { GridBlock } from "@ux/PageContainer"

export default function ContactsPage() {
const { user } = useUserAuth()
const pathname = usePathname() || ""
const { savePageSettings, getPageSettings } = usePageStore()

const userId = user?.id || "guest"

// Load settings from localStorage
const [columns, setColumns] = useState<2 | 3 | 4>(() => {
const saved = usePageStore.getState().getPageSettings(userId, pathname)
return (saved?.columns as 2 | 3 | 4) || 4
})

const [viewMode, setViewMode] = useState<"grid" | "table">(() => {
const saved = usePageStore.getState().getPageSettings(userId, pathname)
return (saved?.viewMode as "grid" | "table") || "grid"
})

// Save columns when changed
const handleColumnsChange = (newColumns: number) => {
setColumns(newColumns as 2 | 3 | 4)
savePageSettings(userId, pathname, { columns: newColumns, viewMode })
}

// Save view mode when changed
const handleViewModeChange = (newMode: "grid" | "table") => {
setViewMode(newMode)
savePageSettings(userId, pathname, { columns, viewMode: newMode })
}

return (
<GridBlock
columns={columns}
onColumnsChange={handleColumnsChange}
viewMode={viewMode}
onViewModeChange={handleViewModeChange}
defaultColumns={4}
showColumnSelector={true}
>
{/* Your cards here */}
</GridBlock>
)
}

What Gets Saved?

The PageSettings type supports:

interface PageSettings {
columns?: 2 | 3 | 4
viewMode?: "grid" | "table"
itemsPerPage?: number
[key: string]: any // Any other custom settings
}

You can save any page-specific UI state:

  • Column count
  • View mode (grid/table)
  • Items per page
  • Sort order
  • Filter states
  • Expanded/collapsed sections
  • Custom preferences

Storage Key Format

Settings are stored with this key format:

aiqlick-page-store → pageSettings → "{userId}:{pathname}"

Examples:

  • "user-123:/company/contacts" - User 123's contacts page settings
  • "user-456:/company/jobs" - User 456's jobs page settings
  • "guest:/jobseeker/jobs" - Guest user's job seeker jobs page

This ensures:

  • ✅ Each user has separate settings
  • ✅ Each page has separate settings
  • ✅ No conflicts between users or pages

Advanced Usage

Save Multiple Settings at Once

savePageSettings(userId, pathname, {
columns: 3,
viewMode: "grid",
itemsPerPage: 20,
sortBy: "name",
sortOrder: "asc",
})

Load Settings with Defaults

const settings = getPageSettings(userId, pathname) || {
columns: 4,
viewMode: "grid",
itemsPerPage: 12,
}

Clear Settings

import { usePageStore } from "@lib/pageStore"

const { clearPageSettings } = usePageStore()
clearPageSettings(userId, pathname)

Create a reusable hook for your page settings:

// lib/lib/hooks/useContactsPageSettings.ts
import { useState, useEffect } from "react"
import { useUserAuth } from "@contexts/UserAuthProvider"
import { usePathname } from "next/navigation"
import { usePageStore } from "@lib/pageStore"

interface ContactsPageSettings {
columns: 2 | 3 | 4
viewMode: "grid" | "table"
itemsPerPage: number
}

export function useContactsPageSettings() {
const { user } = useUserAuth()
const pathname = usePathname() || ""
const { savePageSettings, getPageSettings } = usePageStore()

const userId = user?.id || "guest"

// Load settings
const [settings, setSettings] = useState<ContactsPageSettings>(() => {
const saved = getPageSettings(userId, pathname)
return {
columns: (saved?.columns as 2 | 3 | 4) || 4,
viewMode: (saved?.viewMode as "grid" | "table") || "grid",
itemsPerPage: (saved?.itemsPerPage as number) || 12,
}
})

// Update settings
const updateSettings = (updates: Partial<ContactsPageSettings>) => {
const newSettings = { ...settings, ...updates }
setSettings(newSettings)
savePageSettings(userId, pathname, newSettings)
}

return {
settings,
updateColumns: (columns: 2 | 3 | 4) => updateSettings({ columns }),
updateViewMode: (viewMode: "grid" | "table") => updateSettings({ viewMode }),
updateItemsPerPage: (itemsPerPage: number) => updateSettings({ itemsPerPage }),
}
}

Then use it in your page:

const { settings, updateColumns, updateViewMode } = useContactsPageSettings()

<GridBlock
columns={settings.columns}
onColumnsChange={updateColumns}
viewMode={settings.viewMode}
onViewModeChange={updateViewMode}
/>

Implementation Checklist

When adding persistent settings to a page:

  • Import usePageStore, useUserAuth, and usePathname
  • Get userId from user?.id (with fallback to "guest")
  • Get pathname from usePathname()
  • Initialize state by loading from getPageSettings(userId, pathname)
  • Provide default values for when settings don't exist
  • Save settings in onChange handlers using savePageSettings()
  • Pass controlled values to GridBlock (columns, viewMode, etc.)
  • Test: Change settings → Refresh page → Settings should persist

Common Patterns

Pattern 1: Simple Column Persistence

const [columns, setColumns] = useState<2 | 3 | 4>(() => {
const saved = usePageStore.getState().getPageSettings(userId, pathname)
return (saved?.columns as 2 | 3 | 4) || 4
})

const handleColumnsChange = (cols: number) => {
setColumns(cols as 2 | 3 | 4)
savePageSettings(userId, pathname, { columns: cols })
}

Pattern 2: Multiple Settings

const [settings, setSettings] = useState(() => {
const saved = getPageSettings(userId, pathname) || {}
return {
columns: (saved.columns as 2 | 3 | 4) || 4,
viewMode: (saved.viewMode as "grid" | "table") || "grid",
itemsPerPage: (saved.itemsPerPage as number) || 12,
}
})

const updateSetting = (key: string, value: any) => {
const newSettings = { ...settings, [key]: value }
setSettings(newSettings)
savePageSettings(userId, pathname, newSettings)
}

Pattern 3: useEffect for Complex Logic

useEffect(() => {
// Save whenever settings change
savePageSettings(userId, pathname, {
columns,
viewMode,
itemsPerPage,
sortBy,
sortOrder,
})
}, [columns, viewMode, itemsPerPage, sortBy, sortOrder])

Debugging

Check localStorage

Open browser DevTools → Application → Local Storage → aiqlick-page-store

You should see:

{
"state": {
"pageSettings": {
"user-123:/company/contacts": {
"columns": 3,
"viewMode": "grid"
}
}
},
"version": 0
}

Console Logging

console.log("Loaded settings:", getPageSettings(userId, pathname))
console.log("Saving settings:", { columns, viewMode })

Clear All Settings

// In browser console
localStorage.removeItem('aiqlick-page-store')

FAQs

Q: Do settings work for guest/unauthenticated users? A: Yes! Use userId = user?.id || "guest" to support guest users.

Q: What happens if two users share a computer? A: Each user has separate settings because they have different user IDs.

Q: Can I save settings per company? A: Yes! Use companyId instead of userId as the first parameter, or combine them: ${userId}:${companyId}.

Q: Will this work across devices? A: No, localStorage is per-browser. For cross-device sync, you'd need to save to the backend instead.

Q: How do I migrate to backend storage later? A: The API is the same! Just replace savePageSettings() and getPageSettings() with GraphQL mutations/queries.

Q: Can I save complex objects? A: Yes! The settings are serialized to JSON, so you can save arrays, nested objects, etc.

Files Reference

  • Centralized Page Titles - Centralized page titles
  • HIERARCHICAL_NAVIGATION_SUMMARY.md - Navigation system (legacy doc, removed in repo cleanup)