-
Notifications
You must be signed in to change notification settings - Fork 18
Open
0 / 10 of 1 issue completedDescription
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
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">m²</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));
}
}
};Reactions are currently unavailable
Sub-issues
Metadata
Metadata
Assignees
Labels
No labels
Type
Projects
Status
💡 Ideas