Skip to content

Enhanced Impact Form UI/UX & Figma Design Updates #69

@LuminaEnvision

Description

@LuminaEnvision

Overview

Implement optional detailed impact data collection form with intuitive UX and update Figma designs for mobile-first cleanup submission flow.

Part 1: Figma Design Updates

Design File

Figma: DeCleanup Network

Design Tasks

1. Enhanced Submission Flow Screens

  • Design "Enhanced Impact Report" option screen after photo upload
  • Create multi-step form layout with progress indicator
  • Design input components for each data field (area, weight, waste types, etc.)
  • Create "Quick Select" buttons for common waste types and locations
  • Design mobile keyboard-friendly number inputs
  • Add visual feedback for completed sections

2. Progressive Disclosure Pattern

  • Design collapsed state: "Add detailed impact data (+5 DCU bonus)"
  • Design expanded state with form sections
  • Create smooth transition animations
  • Design section headers with completion checkmarks

3. Incentive Visualization

  • Design bonus badge: "+5 DCU for Enhanced Report"
  • Create "Verified Impact Report" badge for completed submissions
  • Design Hypercert milestone progress indicator (X/10 cleanups)
  • Create celebration modal for reaching 10-cleanup milestone

4. Form Components Library

  • Location type selector (beach, park, street, forest, waterway)
  • Waste type multi-select with icons
  • Area input with unit toggle (m² / ft²)
  • Weight input with unit toggle (kg / lbs)
  • Duration picker (hours + minutes)
  • Bags filled stepper control
  • Text area for observations

5. Mobile Optimization

  • Ensure all inputs are thumb-friendly (min 44px touch targets)
  • Design single-column layout for mobile
  • Create bottom sheet pattern for multi-selects
  • Optimize for one-handed use
  • Add "Save Draft" functionality

6. Empty States & Guidance

  • Design helper text for each field explaining impact
  • Create example submissions for reference
  • Design tooltip system for field explanations
  • Add visual guidelines (e.g., "1 standard trash bag ≈ 2kg")

Design Deliverables

  • Complete form flow screens (6-8 screens)
  • Component library for form inputs
  • Animation specifications
  • Mobile and desktop responsive variants
  • Dark mode versions (if applicable)

Design Principles

  • Mobile-first: Design for smallest screens first
  • Progressive: Basic submission easy, enhanced optional
  • Clear incentives: Show bonus DCU prominently
  • Quick completion: Most fields optional, smart defaults
  • Visual feedback: Show progress and impact clearly

Part 2: Frontend Implementation

Technical Stack

  • React
  • TypeScript
  • Tailwind CSS (core utility classes only)
  • Form library: React Hook Form
  • Wallet integration: existing context

UI/UX Implementation

1. Form Integration

Position in submission flow:

Photo upload → Basic details → [NEW] Enhanced Impact (Optional) → Review → Submit

Component structure:

<CleanupSubmissionFlow>
  <PhotoUpload />
  <BasicDetails />
  <EnhancedImpactForm optional />  {/* NEW */}
  <ReviewSubmission />
  <SubmitButton />
</CleanupSubmissionFlow>

2. Enhanced Impact Form Component

interface EnhancedImpactFormProps {
  onComplete: (data: EnhancedImpactData) => void;
  onSkip: () => void;
}

const EnhancedImpactForm: React.FC<EnhancedImpactFormProps> = ({
  onComplete,
  onSkip
}) => {
  const [isExpanded, setIsExpanded] = useState(false);
  
  return (
    <div className="enhanced-impact-section">
      {!isExpanded ? (
        <button onClick={() => setIsExpanded(true)} className="expand-btn">
          <span>📊 Add detailed impact data</span>
          <span className="bonus-badge">+5 DCU bonus</span>
        </button>
      ) : (
        <FormSections onComplete={onComplete} />
      )}
      <button onClick={onSkip} className="skip-btn">
        Skip (continue with basic submission)
      </button>
    </div>
  );
};

3. Form Sections with Progressive Disclosure

Section 1: Basic Metrics (Always visible first)

  • Area cleaned (m² or ft²)
  • Location type (visual selector with icons)
  • Estimated weight (kg or lbs)
  • Number of bags

Section 2: Waste Details (Expand on tap)

  • Waste types (multi-select chips)
  • Duration (hour + minute picker)

Section 3: Additional Context (Optional, expand on tap)

  • Environmental observations (text area)
  • Prevention suggestions (text area)
  • Equipment used (multi-select)
  • Safety measures (multi-select)

4. Input Components

Location Type Selector:

const locationTypes = [
  { id: 'beach', icon: '🏖️', label: 'Beach' },
  { id: 'park', icon: '🌳', label: 'Park' },
  { id: 'street', icon: '🛣️', label: 'Street' },
  { id: 'forest', icon: '🌲', label: 'Forest' },
  { id: 'waterway', icon: '💧', label: 'Waterway' },
];

<div className="grid grid-cols-2 gap-2">
  {locationTypes.map(type => (
    <button
      key={type.id}
      onClick={() => setValue('locationType', type.id)}
      className={selected === type.id ? 'selected' : ''}
    >
      <span className="text-2xl">{type.icon}</span>
      <span>{type.label}</span>
    </button>
  ))}
</div>

Waste Type Multi-Select:

const wasteTypes = [
  'Plastic Bottles',
  'Cigarette Butts',
  'Food Packaging',
  'Glass',
  'Metal Cans',
  'Paper/Cardboard',
  'Hazardous Materials',
  'Other'
];

<div className="flex flex-wrap gap-2">
  {wasteTypes.map(type => (
    <Chip
      key={type}
      label={type}
      selected={selected.includes(type)}
      onToggle={() => toggleWasteType(type)}
    />
  ))}
</div>

Area Input with Unit Toggle:

<div className="flex gap-2">
  <input
    type="number"
    value={area}
    onChange={(e) => setArea(e.target.value)}
    placeholder="0"
    className="flex-1"
  />
  <select value={unit} onChange={(e) => setUnit(e.target.value)}>
    <option value="sqm"></option>
    <option value="sqft">ft²</option>
  </select>
</div>
<p className="helper-text">Approximate area cleaned</p>

5. Smart Defaults & Auto-completion

// Auto-populate based on location and time
useEffect(() => {
  if (photos.length > 0) {
    // Extract timestamp from photo metadata
    const timestamp = extractPhotoTimestamp(photos[0]);
    setValue('timestamp', timestamp);
    
    // Estimate duration from photo timestamps
    if (photos.length >= 2) {
      const duration = calculateDuration(photos[0], photos[photos.length - 1]);
      setValue('durationMinutes', duration);
    }
  }
}, [photos]);

// Auto-generate scope of work
useEffect(() => {
  if (locationType && wasteTypes.length > 0) {
    const scope = `${locationType} ${wasteTypes.join(', ')} removal`;
    setValue('scopeOfWork', scope);
  }
}, [locationType, wasteTypes]);

6. Progress Indicator

const ProgressIndicator = ({ currentStep, totalSteps, completedFields }) => (
  <div className="progress-bar">
    <div className="progress-fill" style={{ width: `${(currentStep / totalSteps) * 100}%` }} />
    <span className="progress-text">
      {completedFields}/{totalSteps} fields completed
    </span>
  </div>
);

7. Save as Draft

const saveDraft = async (data: Partial<EnhancedImpactData>) => {
  try {
    await window.storage.set(
      `draft:${userAddress}:${Date.now()}`,
      JSON.stringify(data)
    );
    toast.success('Draft saved!');
  } catch (error) {
    console.error('Failed to save draft:', error);
  }
};

// Auto-save every 30 seconds
useEffect(() => {
  const interval = setInterval(() => {
    if (isDirty) {
      saveDraft(getValues());
    }
  }, 30000);
  return () => clearInterval(interval);
}, [isDirty]);

8. Data Validation

const schema = z.object({
  areaCleaned: z.number().min(1).max(1000000).optional(),
  locationType: z.enum(['beach', 'park', 'street', 'forest', 'waterway']).optional(),
  wasteTypes: z.array(z.string()).optional(),
  estimatedWeight: z.number().min(0).max(10000).optional(),
  bagsFilled: z.number().min(0).max(255).optional(),
  durationMinutes: z.number().min(1).max(1440).optional(),
});

// Validation with helpful error messages
const { register, handleSubmit, formState: { errors } } = useForm({
  resolver: zodResolver(schema),
});

9. Bonus DCU Display

const BonusBadge = () => (
  <div className="bonus-badge">
    <span className="bonus-icon">🎁</span>
    <div className="bonus-text">
      <strong>+5 DCU Bonus</strong>
      <small>Complete enhanced form</small>
    </div>
  </div>
);

10. Hypercert Milestone Progress

const HypercertProgress = ({ userCleanups }) => {
  const progress = userCleanups % 10;
  const nextMilestone = Math.ceil(userCleanups / 10) * 10;
  
  return (
    <div className="hypercert-progress">
      <div className="progress-circle">
        <CircularProgress value={(progress / 10) * 100} />
        <span className="progress-number">{progress}/10</span>
      </div>
      <div className="progress-info">
        <p className="font-semibold">Next Hypercert in {10 - progress} cleanups</p>
        <p className="text-sm text-gray-600">
          Permanent impact certificate at {nextMilestone} cleanups
        </p>
      </div>
    </div>
  );
};

11. Privacy Controls

const PrivacySettings = ({ settings, onChange }) => (
  <div className="privacy-settings">
    <h4>Privacy Controls</h4>
    <label>
      <input
        type="checkbox"
        checked={settings.shareLocationData}
        onChange={(e) => onChange('shareLocationData', e.target.checked)}
      />
      Share location data with partners
    </label>
    <label>
      <input
        type="checkbox"
        checked={settings.includeInAnalytics}
        onChange={(e) => onChange('includeInAnalytics', e.target.checked)}
      />
      Include in anonymized analytics
    </label>
    <p className="text-xs text-gray-500">
      Your data helps us measure global impact and attract corporate sponsors
    </p>
  </div>
);

Mobile Optimization

Responsive Design

/* Mobile-first approach */
.enhanced-impact-form {
  padding: 1rem;
}

/* Single column on mobile */
.form-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

/* Two columns on tablet+ */
@media (min-width: 768px) {
  .form-grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* Touch-friendly targets */
.form-button,
.form-input,
.chip {
  min-height: 44px;
  min-width: 44px;
}

Keyboard Handling

// Optimize for mobile keyboards
<input
  type="number"
  inputMode="decimal"  // Shows decimal keyboard on mobile
  pattern="[0-9]*"
  placeholder="0"
/>

// Prevent zoom on input focus (iOS)
<input style={{ fontSize: '16px' }} />

Implementation Tasks

Phase 1: Design & Structure

  • Complete Figma designs for all form screens
  • Create component library in Figma
  • Get design approval
  • Export design assets and specifications

Phase 2: Core Form Components

  • Build location type selector
  • Build waste type multi-select
  • Build number inputs with unit toggles
  • Build duration picker
  • Build text areas for context
  • Build privacy settings toggle

Phase 3: Form Logic & State

  • Implement form state management (React Hook Form)
  • Add validation with error messages
  • Implement smart defaults and auto-completion
  • Add save draft functionality
  • Integrate with existing submission flow

Phase 4: Visual Feedback & Incentives

  • Add progress indicator
  • Implement bonus DCU badge
  • Create Hypercert milestone progress widget
  • Build celebration modal for milestones
  • Add "Verified Impact Report" badge to submissions

Phase 5: Smart Contract Integration

  • Connect form submission to claimWithEnhancedData() contract function
  • Handle enhanced data bonus minting
  • Display transaction confirmations
  • Error handling for failed transactions

Phase 6: Testing & Optimization

  • Mobile responsiveness testing (iOS & Android)
  • Accessibility testing (screen readers, keyboard navigation)
  • Performance optimization (lazy loading, code splitting)
  • User testing with 5-10 real users
  • A/B test completion rates with/without bonus incentive

Acceptance Criteria

  • Form integrates seamlessly into existing submission flow
  • All fields capture data correctly
  • Mobile UX smooth with no zoom/scroll issues
  • Save draft works correctly
  • Bonus DCU (+5) displays prominently
  • Hypercert progress (X/10) visible on dashboard
  • Privacy controls function properly
  • Form submission triggers smart contract correctly
  • Enhanced submissions get "Verified Impact Report" badge
  • Completion rates improve by 20%+ vs basic submission

Analytics & Success Metrics

Track the following metrics:

  • Enhanced form completion rate
  • Average time to complete enhanced form
  • Most commonly selected waste types and locations
  • Correlation between enhanced data and user retention
  • Bonus DCU claimed vs total submissions
  • User feedback on form UX

Localization Support

// Unit conversion for international users
const convertUnits = (value: number, from: string, to: string) => {
  const conversions = {
    'sqm_to_sqft': value * 10.764,
    'sqft_to_sqm': value / 10.764,
    'kg_to_lbs': value * 2.205,
    'lbs_to_kg': value / 2.205,
  };
  return conversions[`${from}_to_${to}`] || value;
};

// Auto-detect user's preferred units
const preferredUnits = useMemo(() => {
  const locale = navigator.language;
  return locale.startsWith('en-US') 
    ? { area: 'sqft', weight: 'lbs' }
    : { area: 'sqm', weight: 'kg' };
}, []);

Error Handling & Edge Cases

// Handle offline submissions
const submitWithOfflineSupport = async (data) => {
  try {
    await submitToBlockchain(data);
  } catch (error) {
    if (!navigator.onLine) {
      // Save to local storage for later sync
      await saveOfflineSubmission(data);
      toast.info('Saved offline. Will sync when connected.');
    } else {
      toast.error('Submission failed. Please try again.');
    }
  }
};

// Handle incomplete drafts
const recoverDrafts = async () => {
  const draftKeys = await window.storage.list('draft:' + userAddress);
  if (draftKeys.keys.length > 0) {
    const shouldRecover = confirm('Found saved draft. Continue editing?');
    if (shouldRecover) {
      const draft = await window.storage.get(draftKeys.keys[0]);
      loadDraftData(JSON.parse(draft.value));
    }
  }
};

Sub-issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    💡 Ideas

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions