Files
Sauci/docs/pack-icons-admin-first.md
T
Jamie BruntonandClaude Opus 4.5 43fa7033dc Add pack icon system and E2EE removal plan
- Replace emoji icons with Ionicons for professional appearance
- Improve E2EE key recovery with better diagnostics
- Add analytics for pack icon events
- Document E2EE removal plan for future simplification

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 15:34:25 +00:00

8.3 KiB

Pack Icons: Admin-First Approach

Problem Statement

The current pack icon system uses emojis stored in the database, which creates a "AI slop" appearance. We've added a frontend mapping from emojis to Ionicons, but this is fragile:

  • New packs require manual code changes to add mappings
  • The mapping is hidden from admins
  • It's a maintenance burden

Solution: Admin-First Icon Selection

Allow admins to select Ionicons directly in the admin UI, storing the Ionicon name (e.g., "briefcase-outline") in the database instead of emojis.

Backwards Compatibility

Important: We must maintain backwards compatibility with the app currently in App Store review.

App Version DB has emoji "💼" DB has "briefcase-outline"
Old (in review) Shows emoji Shows literal text (broken)
New (with mapping) Maps to Ionicon Uses directly

Strategy

  1. Don't migrate existing data - existing packs keep their emojis
  2. New packs use Ionicon names - admin UI stores Ionicon names
  3. Mobile handles both formats - detect format and handle appropriately

This ensures:

  • Old app continues working with existing emoji packs
  • New packs show default icon on old app (acceptable degradation)
  • New app handles everything correctly

Implementation Tasks

Task 1: Create Ionicon Picker Component (Admin)

File: apps/admin/src/components/ui/icon-picker.tsx (new file)

Create a new component that displays a grid of available Ionicons for selection.

Requirements:

  • Display commonly used Ionicons in a grid/dropdown
  • Show icon preview with name
  • Search/filter functionality (optional)
  • Return the Ionicon name string (e.g., "briefcase-outline")

Suggested Icons to Include:

const AVAILABLE_ICONS = [
  // Relationships & Love
  'heart-outline', 'heart-half-outline', 'heart-circle-outline',

  // Communication
  'chatbubbles-outline', 'chatbox-outline', 'mail-outline',

  // Romance & Dates
  'flower-outline', 'wine-outline', 'restaurant-outline', 'cafe-outline',

  // Adventure & Travel
  'airplane-outline', 'car-outline', 'compass-outline', 'map-outline',

  // Home & Family
  'home-outline', 'people-outline', 'person-outline',

  // Mystery & Secrets
  'eye-off-outline', 'key-outline', 'lock-closed-outline',

  // Fun & Games
  'dice-outline', 'gift-outline', 'sparkles-outline', 'star-outline',

  // Intimacy
  'flame-outline', 'flash-outline', 'moon-outline', 'sunny-outline',

  // Goals & Planning
  'flag-outline', 'calendar-outline', 'checkbox-outline', 'trophy-outline',

  // General
  'layers-outline', 'cube-outline', 'folder-outline', 'bookmark-outline',
  'bulb-outline', 'color-wand-outline', 'sync-outline', 'refresh-outline',
];

Component Interface:

interface IconPickerProps {
  value: string;
  onChange: (iconName: string) => void;
}

Task 2: Update Pack Form Dialog (Admin)

File: apps/admin/src/components/content/PackFormDialog.tsx

Changes:

  1. Import new IconPicker component
  2. Replace EmojiPicker with IconPicker for the icon field

Current code (line ~101-104):

<EmojiPicker
    value={formData.icon}
    onChange={(emoji) => setField('icon', emoji)}
/>

New code:

<IconPicker
    value={formData.icon}
    onChange={(iconName) => setField('icon', iconName)}
/>
  1. Update default icon in initialFormData (line ~41):
// Change from '💕' to:
icon: 'heart-outline',

Task 3: Update Category Form (Admin)

File: apps/admin/src/pages/content/CategoriesPage.tsx

Same changes as Task 2 - replace EmojiPicker with IconPicker for category icons.


Task 4: Update AI Pack Generator (Admin)

File: apps/admin/src/lib/ai/generators/packs.ts

Update the AI prompt to suggest Ionicon names instead of emojis.

Current (line ~147):

- icon: A single descriptive emoji

New:

- icon: An Ionicon name from this list: heart-outline, flame-outline, sparkles-outline, gift-outline, wine-outline, airplane-outline, home-outline, key-outline, flash-outline, sunny-outline, flower-outline, star-outline, dice-outline, compass-outline, bulb-outline

Task 5: Update Mobile Icon Utility

File: apps/mobile/src/lib/packIcons.ts

Update getPackIconName() to handle both Ionicon names and legacy emojis.

New implementation:

import type { Ionicons } from "@expo/vector-icons";

type IoniconsName = keyof typeof Ionicons.glyphMap;

// Legacy emoji mappings (for backwards compatibility with existing packs)
const EMOJI_TO_IONICON: Record<string, IoniconsName> = {
    "💼": "briefcase-outline",
    "🔗": "heart-half-outline",
    "❤️": "heart-outline",
    "💫": "sparkles-outline",
    "🤫": "eye-off-outline",
    "🗝️": "key-outline",
    "🌹": "flower-outline",
    "🍷": "wine-outline",
    "✨": "sparkles-outline",
    "✈️": "airplane-outline",
    "🚗": "car-outline",
    "🏡": "home-outline",
    "🎭": "color-wand-outline",
    "🎲": "dice-outline",
    "🎁": "gift-outline",
    "🔄": "sync-outline",
    "😈": "flash-outline",
    "🔥": "flame-outline",
    "🎯": "flag-outline",
    "☀️": "sunny-outline",
    "📦": "cube-outline",
    "📁": "folder-outline",
};

export const DEFAULT_PACK_ICON: IoniconsName = "layers-outline";

// List of valid Ionicon names (subset we support)
const VALID_IONICONS = new Set([
    'heart-outline', 'heart-half-outline', 'heart-circle-outline',
    'chatbubbles-outline', 'chatbox-outline', 'mail-outline',
    'flower-outline', 'wine-outline', 'restaurant-outline', 'cafe-outline',
    'airplane-outline', 'car-outline', 'compass-outline', 'map-outline',
    'home-outline', 'people-outline', 'person-outline',
    'eye-off-outline', 'key-outline', 'lock-closed-outline',
    'dice-outline', 'gift-outline', 'sparkles-outline', 'star-outline',
    'flame-outline', 'flash-outline', 'moon-outline', 'sunny-outline',
    'flag-outline', 'calendar-outline', 'checkbox-outline', 'trophy-outline',
    'layers-outline', 'cube-outline', 'folder-outline', 'bookmark-outline',
    'bulb-outline', 'color-wand-outline', 'sync-outline', 'refresh-outline',
    'briefcase-outline',
]);

/**
 * Converts an icon value to an Ionicons name.
 * Handles both:
 * - Ionicon names directly (new packs): "briefcase-outline" -> "briefcase-outline"
 * - Legacy emojis (existing packs): "💼" -> "briefcase-outline"
 */
export function getPackIconName(icon: string | null | undefined): IoniconsName {
    if (!icon) return DEFAULT_PACK_ICON;

    // Check if it's already a valid Ionicon name
    if (VALID_IONICONS.has(icon)) {
        return icon as IoniconsName;
    }

    // Fall back to emoji mapping for legacy data
    return EMOJI_TO_IONICON[icon] || DEFAULT_PACK_ICON;
}

Task 6: Add Ionicons Package to Admin (if needed)

File: apps/admin/package.json

The admin app may need the Ionicons package to display icon previews.

cd apps/admin
npm install react-icons

Then use IoIcons from react-icons/io5 which matches Ionicons naming.

Alternatively, create simple SVG components or use icon font directly.


File Summary

File Action Priority
apps/admin/src/components/ui/icon-picker.tsx Create High
apps/admin/src/components/content/PackFormDialog.tsx Modify High
apps/admin/src/pages/content/CategoriesPage.tsx Modify Medium
apps/admin/src/lib/ai/generators/packs.ts Modify Low
apps/mobile/src/lib/packIcons.ts Modify High
apps/admin/package.json Modify (maybe) Medium

Testing Checklist

  • Create a new pack in admin with Ionicon - verify it saves correctly
  • Edit an existing pack (with emoji) - verify emoji still displays in picker
  • Mobile app displays new Ionicon packs correctly
  • Mobile app displays legacy emoji packs correctly (via mapping)
  • Old app version (if testable) shows default icon for new Ionicon packs

Future Considerations

Once the new app version is widely deployed:

  1. Optional: Run a database migration to convert remaining emojis to Ionicons
  2. Optional: Remove emoji mapping code from mobile app
  3. Optional: Add migration script admins can run per-pack

For now, the backwards-compatible approach means no database migrations and no breaking changes.