Skip to main content

Persistent Settings Implementation - Complete Summary

✅ Implementation Complete

The contacts page now saves and restores user preferences automatically!

What Was Implemented

Settings That Persist

  1. Column Count (2, 3, or 4 columns)

    • User selects columns via button in top right
    • Saved immediately when changed
    • Restored on page load
  2. Items Per Page (10, 20, 30, 40, or 50)

    • User selects from dropdown in pagination area
    • Saved immediately when changed
    • Restored on page load

Storage Details

  • Storage: localStorage (browser-based)
  • Key Format: "{userId}:{pathname}"
  • Scope: User-specific AND page-specific
  • Persistence: Survives page refreshes and browser restarts

Files Changed

app/company/contacts/page.tsx

Imports Added:

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

State Added:

const pathname = usePathname() || ""
const { savePageSettings, getPageSettings } = usePageStore()
const userId = user?.id || "guest"

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

// Load items per page from localStorage
const [itemsPerPage, setItemsPerPage] = useState<number>(() => {
const saved = usePageStore.getState().getPageSettings(userId, pathname)
return (saved?.itemsPerPage as number) || 10
})

Handlers Added:

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

// Save items per page when changed
const handlePaginationChange = (state: any) => {
if (state.itemsPerPage !== itemsPerPage) {
setItemsPerPage(state.itemsPerPage)
savePageSettings(userId, pathname, { columns, itemsPerPage: state.itemsPerPage })
}
}

GridBlock Updated:

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

How It Works

Flow Diagram

┌─────────────────────────────────────────────────┐
│ 1. User Opens /company/contacts │
└─────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────┐
│ 2. Component Loads │
│ - Get userId from useUserAuth() │
│ - Get pathname from usePathname() │
│ - Call getPageSettings(userId, pathname) │
└─────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────┐
│ 3. Initialize State │
│ - columns = saved?.columns || 4 │
│ - itemsPerPage = saved?.itemsPerPage || 10 │
└─────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────┐
│ 4. Render GridBlock with Saved Settings │
│ - Show N columns │
│ - Show M items per page │
└─────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────┐
│ 5. User Changes Setting │
│ - Click column button (2, 3, or 4) │
│ - OR select items per page dropdown │
└─────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────┐
│ 6. Handler Called │
│ - handleColumnsChange(newColumns) │
│ - OR handlePaginationChange(state) │
└─────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────┐
│ 7. Save to localStorage │
│ savePageSettings(userId, pathname, { │
│ columns: N, │
│ itemsPerPage: M │
│ }) │
└─────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────┐
│ 8. Settings Persisted! │
│ localStorage["aiqlick-page-store"] = { │
│ pageSettings: { │
│ "userId:pathname": { columns, items } │
│ } │
│ } │
└─────────────────────────────────────────────────┘

localStorage Structure

{
"state": {
"pageSettings": {
"user-123:/company/contacts": {
"columns": 3,
"itemsPerPage": 20
},
"user-123:/company/jobs": {
"columns": 4,
"itemsPerPage": 10
},
"user-456:/company/contacts": {
"columns": 2,
"itemsPerPage": 50
}
}
},
"version": 0
}

Key Format: "{userId}:{pathname}"

This ensures:

  • ✅ Different users have separate settings
  • ✅ Different pages have separate settings
  • ✅ Same user on same page always gets same settings

Test Scenarios

Scenario 1: Basic Persistence

  1. Set 3 columns
  2. Refresh page
  3. ✅ Still shows 3 columns

Scenario 2: Multiple Settings

  1. Set 2 columns and 30 items per page
  2. Refresh page
  3. ✅ Still shows 2 columns and 30 items

Scenario 3: Multiple Users

  1. User A sets 2 columns
  2. User B sets 4 columns
  3. ✅ Each user sees their own settings

Scenario 4: Multiple Pages

  1. Contacts: 3 columns, 20 items
  2. Jobs: 4 columns, 10 items
  3. ✅ Each page remembers its own settings

Scenario 5: Browser Restart

  1. Set 2 columns and 40 items
  2. Close browser
  3. Reopen browser
  4. ✅ Still shows 2 columns and 40 items

Adding to Other Pages

To add persistent settings to another page (e.g., Jobs, Candidates), follow this pattern:

Step 1: Import Dependencies

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

Step 2: Get User and Path

const { user } = useUserAuth()
const pathname = usePathname() || ""
const { savePageSettings } = usePageStore()
const userId = user?.id || "guest"

Step 3: Load Settings

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

Step 4: Save on Change

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

Step 5: Pass to GridBlock

<GridBlock
columns={columns}
onColumnsChange={handleColumnsChange}
/>

System Architecture

pageStore (Zustand with Persist)

lib/pageStore.ts

  • Zustand store with persist middleware
  • Saves to localStorage automatically
  • Only persists pageSettings (not temporary page info)

Methods:

  • savePageSettings(userId, pathname, settings) - Save settings
  • getPageSettings(userId, pathname) - Load settings
  • clearPageSettings(userId, pathname) - Clear settings

PageSettings Type

lib/types/pagestore.ts

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

Future Enhancements

Additional Settings to Save

  1. View Mode (grid vs table)
  2. Sort Order (name, date, etc.)
  3. Filter State (active filters)
  4. Search Term (current search)
  5. Expanded/Collapsed Sections
  6. Custom Display Options

Backend Sync (Optional)

Currently uses localStorage (client-only). For cross-device sync:

  1. Add GraphQL mutations to save settings to backend
  2. Replace savePageSettings() with API call
  3. Keep same interface - no page code changes needed!

Documentation

Benefits Achieved

Better UX - Users don't have to reset preferences every time ✅ User-specific - Each user has their own preferences ✅ Page-specific - Different pages remember different settings ✅ Persistent - Survives refreshes and browser restarts ✅ Simple API - Easy to add to new pages ✅ Type-safe - Full TypeScript support ✅ Extensible - Easy to add new settings types

Production Ready ✅

The implementation is:

  • ✅ Tested and working
  • ✅ TypeScript error-free
  • ✅ Documented
  • ✅ Follows established patterns
  • ✅ Ready for deployment

Users can now enjoy a personalized experience that remembers their preferences!