Skip to main content

Running Phase 2 Improvements

This guide provides detailed instructions for verifying that Phase 2 improvements are working correctly and how to see the UX enhancements in action.
Prerequisites: Ensure you have completed Phase 1 and have Terra running locally.

Quick Verification (2 minutes)

Run these commands to verify Phase 2 is working:
# Navigate to Terra directory
cd apps/terra

# 1. Check that loading states exist
ls src/app/\(dashboard\)/loading.tsx
ls src/app/\(dashboard\)/forms/loading.tsx
ls src/app/\(dashboard\)/forms/\[formId\]/submissions/loading.tsx
ls src/app/\(dashboard\)/forms/\[formId\]/edit/loading.tsx

# 2. Check Next.js config
cat next.config.ts | grep -A 10 "images:"

# 3. Start dev server
pnpm dev
Expected results:
  • ✅ All 4 loading.tsx files exist
  • ✅ next.config.ts has image optimization configured
  • ✅ Dev server starts without errors

Step 1: Verify Loading States

Loading states provide visual feedback while data is being fetched.

Test Dashboard Loading

  1. Start the development server:
    pnpm dev
    
  2. Navigate to the dashboard at http://localhost:3000
  3. You should see (for a brief moment):
    • ✅ Dark gradient HeroCard skeleton
    • ✅ 3 metric card skeletons with shimmer animation
    • ✅ Programs table skeleton with 5 rows
    • ✅ Smooth transition to actual data
  4. Simulate slow network (Chrome DevTools):
    • Open DevTools (F12)
    • Go to Network tab
    • Select “Slow 3G” from throttling dropdown
    • Refresh the page
    • You’ll see skeletons for longer

Test Forms List Loading

  1. Navigate to /forms
  2. You should see:
    • ✅ Workspace sidebar skeleton on the left
    • ✅ Header skeleton with title and buttons
    • ✅ Tabs skeleton (Active, Templates, Archived)
    • ✅ Table skeleton with 8 rows
    • ✅ Shimmer animation on all skeletons

Test Submissions Loading

  1. Navigate to /forms/[any-form-id]/submissions
  2. You should see:
    • ✅ Header with “Submissions” title skeleton
    • ✅ Export button skeleton
    • ✅ Table skeleton with 10 rows and 5 columns
    • ✅ Pagination controls skeleton at bottom

Test Form Builder Loading

  1. Navigate to /forms/[any-form-id]/edit
  2. You should see:
    • ✅ Toolbox skeleton on the left (4 sections)
    • ✅ Canvas skeleton in the center (5 field skeletons)
    • ✅ Properties panel skeleton on the right
    • ✅ Floating save button skeleton in bottom right
    • ✅ Full 3-column layout preserved
Loading states are automatically shown by Next.js when a page is loading. They use the loading.tsx file in the same directory as page.tsx.

Step 2: Verify Image Optimization

Next.js Image component provides automatic optimization, lazy loading, and modern formats.

Check Network Tab for Optimized Images

  1. Open Chrome DevTools (F12)
  2. Go to Network tab
  3. Navigate to a page with images:
    • Public form page: /p/[slug]
    • Dashboard with program cards: /portals
    • Form settings branding: /forms/[formId]/settings/branding
  4. Filter by “Img” in Network tab
  5. You should see:
    • ✅ Images served as .webp or .avif (modern formats)
    • ✅ Multiple sizes available (srcset)
    • ✅ Images only load when scrolled into view (lazy loading)
    • ✅ Smaller file sizes compared to original
Example Network Request:
GET /_next/image?url=https%3A%2F%2Fproject.supabase.co%2Fstorage%2Fv1%2Fobject%2Fpublic%2Fform-uploads%2Fcover.jpg&w=1080&q=75
Status: 200
Type: webp
Size: 45.2 KB (was 120 KB as JPEG)

Verify Image Component Usage

Check that images are using Next.js Image:
# Should NOT find <img tags in these files (except in comments)
grep -n "<img" src/components/engine/fields/image-field.tsx
grep -n "<img" src/app/p/[slug]/client.tsx
grep -n "<img" src/components/public/public-header.tsx

# Should find Next.js Image imports
grep -n "import.*Image.*from.*next/image" src/components/engine/fields/image-field.tsx
Expected:
  • ✅ No <img> tags in updated files
  • import Image from "next/image" present
  • ✅ Images use <Image> component

Test Responsive Images

  1. Open a page with images (e.g., public form with cover image)
  2. Open DevToolsToggle device toolbar (Ctrl+Shift+M)
  3. Switch between device sizes:
    • Mobile (375px)
    • Tablet (768px)
    • Desktop (1920px)
  4. Check Network tab - you should see:
    • ✅ Different image sizes loaded for different viewport widths
    • ✅ Smaller images on mobile (e.g., 828w)
    • ✅ Larger images on desktop (e.g., 1920w)

Test Lazy Loading

  1. Navigate to a page with multiple images (e.g., forms list with cover images)
  2. Open Network tab and clear it
  3. Scroll down slowly
  4. You should see:
    • ✅ Images only load when they enter the viewport
    • ✅ Images below the fold don’t load immediately
    • ✅ Network requests appear as you scroll

Step 3: Verify Image Configuration

Check that Next.js is configured correctly.

Inspect next.config.ts

cat apps/terra/next.config.ts
Should contain:
images: {
  formats: ["image/avif", "image/webp"],
  deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
  imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  remotePatterns: [
    {
      protocol: "https",
      hostname: "**.supabase.co",
      pathname: "/storage/v1/object/**",
    },
  ],
},

Test Remote Image Loading

  1. Upload a test image to a form (cover image or logo)
  2. Navigate to the form (public or settings page)
  3. You should see:
    • ✅ Image loads without console errors
    • ✅ Image is optimized (check Network tab for .webp)
    • ✅ No “Invalid src” errors in console
If you see errors like “Invalid src prop”, ensure the image URL matches the remotePatterns in next.config.ts. Supabase URLs must include /storage/v1/object/.

Step 4: Performance Comparison

Measure the performance improvements.

Before/After File Sizes

Use the Network tab to compare: Before (using <img>):
cover.jpg: 250 KB
logo.png: 45 KB
Total: 295 KB
After (using Next.js Image):
cover.webp: 85 KB (66% smaller)
logo.webp: 12 KB (73% smaller)
Total: 97 KB (67% reduction)

Lighthouse Score Improvements

  1. Open DevToolsLighthouse tab
  2. Run audit on a page with images (e.g., public form)
  3. Compare scores:
    • Performance: Should improve 5-15 points
    • Best Practices: Should score 100 (modern image formats)
    • LCP (Largest Contentful Paint): Should improve
Expected improvements:
  • ✅ “Serve images in modern formats” - PASSED
  • ✅ “Properly size images” - PASSED
  • ✅ “Defer offscreen images” - PASSED
  • ✅ LCP improved by 0.5-1.5 seconds

Common Issues & Solutions

Issue: “Invalid src prop” error

Error:
Error: Invalid src prop (https://example.com/image.jpg) on `next/image`, hostname "example.com" is not configured under images in your `next.config.ts`.
Solution: Add the hostname to remotePatterns:
// next.config.ts
remotePatterns: [
  {
    protocol: "https",
    hostname: "example.com",
  },
  // ... existing patterns
],

Issue: Images appear distorted or cropped

Problem: Image aspect ratio doesn’t match container Solution: Use proper layout:
// For fixed aspect ratio
<div className="relative w-full aspect-video">
  <Image src={src} alt={alt} fill className="object-cover" />
</div>

// For flexible dimensions
<Image src={src} alt={alt} width={800} height={600} className="w-full h-auto" />

Issue: Loading states flash too quickly

Not really an issue: This is good! Your app is fast. If you want to see them longer (for demo purposes):
// Add artificial delay (DEVELOPMENT ONLY)
await new Promise(resolve => setTimeout(resolve, 2000));

Issue: Images don’t load in production

Solution: Ensure environment variables are set in Vercel/production:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co

Daily Development Workflow

Using Loading States

When creating new pages:
  1. Create page.tsx first
  2. Create loading.tsx in the same directory
  3. Match the layout of your page.tsx
Example:
// app/new-page/loading.tsx
import { Skeleton } from "@unify/ui";

export default function NewPageLoading() {
  return (
    <div className="p-6 space-y-4">
      <Skeleton className="h-8 w-64" /> {/* Title */}
      <Skeleton className="h-4 w-full" /> {/* Description */}
      <Skeleton className="h-32 w-full" /> {/* Content */}
    </div>
  );
}

Using Next.js Image

When adding images:
// ❌ OLD WAY - Don't use <img>
<img src="/logo.png" alt="Logo" className="h-10 w-auto" />

// ✅ NEW WAY - Use Next.js Image
import Image from "next/image";

// Fixed dimensions
<Image src="/logo.png" alt="Logo" width={40} height={40} />

// Responsive (fill container)
<div className="relative h-10 w-32">
  <Image src="/logo.png" alt="Logo" fill className="object-contain" />
</div>

Metrics & Impact

Loading States Impact

User Experience:
  • ✅ Perceived performance improved (feels faster)
  • ✅ No flash of empty content
  • ✅ Professional, polished loading experience
  • ✅ Consistent visual feedback across all pages
Developer Experience:
  • ✅ Easy to add (just create loading.tsx)
  • ✅ Automatic with Next.js App Router
  • ✅ Reusable Skeleton component

Image Optimization Impact

Performance:
  • ✅ 50-70% reduction in image file sizes
  • ✅ Faster page loads (0.5-1.5s improvement)
  • ✅ Better Core Web Vitals scores
  • ✅ Automatic lazy loading
Cost Savings:
  • ✅ Reduced bandwidth usage
  • ✅ Lower Vercel/hosting bills
  • ✅ Faster for users on slow connections
SEO:
  • ✅ Improved Lighthouse scores
  • ✅ Better mobile performance
  • ✅ Modern image format support

Next Steps

✅ Phase 2 Days 4-5 complete! Now you can:
  1. Continue to Days 6-7 - Add accessibility and mobile responsiveness
  2. Monitor performance using Lighthouse and Core Web Vitals
  3. Add loading states to any new pages you create
  4. Always use Next.js Image for all images going forward
Track progress in Quality Improvements Guide

Getting Help

If you encounter issues:
  1. Check this guide first
  2. Verify next.config.ts has correct image configuration
  3. Check browser console for errors
  4. Review Next.js Image documentation
Useful resources: