Files
tilbudgivern/frontend/src/components/smartPackages/QuickStartDialog.js
T
alexpolo1 b93784b340 feat: Massiv UX forbedring af Smart Pakker - Nem wizard og hjælp
🎯 Problemet: Kunder synes det er svært at lave smart pakker
✅ Løsningen: Komplet redesign med guidet oprettelse

🚀 Nye Funktioner:

1. SMART PACKAGE WIZARD (SmartPackageWizard.js)
   - Trin-for-trin guide gennem 4 nemme steps
   - Trin 1: Grundinfo med templates og tooltips
   - Trin 2: Materialer med visuelt overblik
   - Trin 3: Opgaver med auto-beregning
   - Trin 4: Gennemgang før gemning
   - Indbygget validation på hvert trin
   - Auto-save i edit mode
   - Responsive design (mobil + desktop)

2. QUICK START DIALOG (QuickStartDialog.js)
   - Vælg mellem 3 oprettelsesmetoder:
     * Guidet Wizard (anbefalet for begyndere)
     * Start med Skabelon (hurtigst)
     * Avanceret (fuld kontrol)
   - Visuelle cards med ikoner og forklaring
   - Template selector med preview

3. HJÆLPE-PANEL (SmartPackagesHelpPanel.js)
   - Sticky sidebar med kontekstuel hjælp
   - "Kom i gang" guide i 4 trin
   - Tips & Tricks sektion
   - "Undgå disse fejl" warnings
   - Tommelfingerregler (timepris, buffer, spild)
   - Kan åbnes/lukkes efter behov
   - Drawer på mobil

4. INTEGRATION AF CARPENTER UX KOMPONENTER
   - FormField: Real-time validation på alle inputs
   - Tooltips: Hjælpetekst ved svære felter
   - AutosaveIndicator: Viser gem-status
   - LoadingSpinner: Bedre loading states

💡 UX Forbedringer:

✓ Klare instruktioner ved hvert trin
✓ Visual feedback (ikoner, farver, progress)
✓ Foreslåede værdier (standard timepris: 580 kr)
✓ Template system til hurtig start
✓ Automatisk beregning af totaler
✓ Fejlmeddelelser med forklaringer
✓ Responsivt design (mobil/tablet/desktop)
✓ Hjælp altid tilgængelig
✓ Kan ikke gå videre uden at udfylde påkrævet
✓ Gennemse alt før gemning

📊 Validering:
- Pakkenavn: min 3 tegn
- Beskrivelse: min 10 tegn
- Timepris: 100-2000 kr.
- Mindst 1 materiale
- Mindst 1 opgave
- Estimeret tid > 0

🎨 Visuelle Elementer:
- Stepper viser fremskridt
- Alert boxes med vigtige tips
- Ikoner for hver sektion
- Chips for templates
- Cards for materialer/opgaver
- Farvekodet totaler (grøn for success)

📱 Responsive Features:
- Hjælpepanel: Sidebar på desktop, drawer på mobil
- Grid layouts tilpasser sig skærmstørrelse
- Touch-venlige buttons
- Optimeret scrolling

🔧 Tekniske Detaljer:
- Bruger useState hooks for lokal state
- useEffect for data loading
- Axios for API kald
- Material-UI komponenter
- React Beautiful DnD ready
- Validering før navigation
- Auto-save med 2s debounce

Dette gør det 10x nemmere at lave smart pakker! 🎉
2025-12-23 00:20:03 +00:00

228 lines
8.8 KiB
JavaScript

import React, { useState } from 'react';
import {
Dialog, DialogTitle, DialogContent, DialogActions,
Button, Grid, Card, CardContent, Typography, Box,
Alert, Chip, RadioGroup, FormControlLabel, Radio
} from '@mui/material';
import {
Rocket, AutoAwesome, Build, Close
} from '@mui/icons-material';
/**
* Quick Start Dialog - hjælper brugeren med at vælge hvordan de vil starte
*/
const QuickStartDialog = ({ open, onClose, onSelectMode, templates }) => {
const [selectedMode, setSelectedMode] = useState('wizard');
const [selectedTemplate, setSelectedTemplate] = useState(null);
const handleStart = () => {
if (selectedMode === 'template' && selectedTemplate) {
onSelectMode('template', selectedTemplate);
} else {
onSelectMode(selectedMode);
}
onClose();
};
return (
<Dialog open={open} onClose={onClose} maxWidth="md" fullWidth>
<DialogTitle>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography variant="h6">
🚀 Kom i gang med Smart Pakker
</Typography>
<Button onClick={onClose} size="small">
<Close />
</Button>
</Box>
</DialogTitle>
<DialogContent>
<Alert severity="info" sx={{ mb: 3 }}>
<Typography variant="body2">
Vælg hvordan du vil oprette din smart pakke. Vi anbefaler at starte med wizarden hvis det er første gang.
</Typography>
</Alert>
<RadioGroup value={selectedMode} onChange={(e) => setSelectedMode(e.target.value)}>
<Grid container spacing={2}>
{/* Wizard Mode */}
<Grid item xs={12} md={4}>
<Card
variant="outlined"
sx={{
cursor: 'pointer',
border: selectedMode === 'wizard' ? 2 : 1,
borderColor: selectedMode === 'wizard' ? 'primary.main' : 'divider',
'&:hover': { borderColor: 'primary.main' }
}}
onClick={() => setSelectedMode('wizard')}
>
<CardContent>
<FormControlLabel
value="wizard"
control={<Radio />}
label=""
sx={{ m: 0, display: 'none' }}
/>
<Box sx={{ textAlign: 'center' }}>
<Rocket sx={{ fontSize: 48, color: 'primary.main', mb: 2 }} />
<Typography variant="h6" gutterBottom>
Guidet Wizard
</Typography>
<Chip label="Anbefalet" color="success" size="small" sx={{ mb: 1 }} />
<Typography variant="body2" color="textSecondary">
Nem trin-for-trin guide der hjælper dig igennem hele processen
</Typography>
<Typography variant="caption" display="block" sx={{ mt: 2, color: 'primary.main' }}>
✓ Perfekt til begyndere
<br />
✓ Ingen vigtige felter glemmes
<br />
✓ Hjælpetekst undervejs
</Typography>
</Box>
</CardContent>
</Card>
</Grid>
{/* Template Mode */}
<Grid item xs={12} md={4}>
<Card
variant="outlined"
sx={{
cursor: 'pointer',
border: selectedMode === 'template' ? 2 : 1,
borderColor: selectedMode === 'template' ? 'primary.main' : 'divider',
'&:hover': { borderColor: 'primary.main' }
}}
onClick={() => setSelectedMode('template')}
>
<CardContent>
<FormControlLabel
value="template"
control={<Radio />}
label=""
sx={{ m: 0, display: 'none' }}
/>
<Box sx={{ textAlign: 'center' }}>
<AutoAwesome sx={{ fontSize: 48, color: 'secondary.main', mb: 2 }} />
<Typography variant="h6" gutterBottom>
Start med Skabelon
</Typography>
<Chip label="Hurtigst" color="info" size="small" sx={{ mb: 1 }} />
<Typography variant="body2" color="textSecondary">
Brug en færdiglavet skabelon og tilpas den til dine behov
</Typography>
<Typography variant="caption" display="block" sx={{ mt: 2, color: 'secondary.main' }}>
✓ Spar tid
<br />
✓ Best practices inkluderet
<br />
✓ Klar til brug
</Typography>
</Box>
</CardContent>
</Card>
</Grid>
{/* Advanced Mode */}
<Grid item xs={12} md={4}>
<Card
variant="outlined"
sx={{
cursor: 'pointer',
border: selectedMode === 'advanced' ? 2 : 1,
borderColor: selectedMode === 'advanced' ? 'primary.main' : 'divider',
'&:hover': { borderColor: 'primary.main' }
}}
onClick={() => setSelectedMode('advanced')}
>
<CardContent>
<FormControlLabel
value="advanced"
control={<Radio />}
label=""
sx={{ m: 0, display: 'none' }}
/>
<Box sx={{ textAlign: 'center' }}>
<Build sx={{ fontSize: 48, color: 'warning.main', mb: 2 }} />
<Typography variant="h6" gutterBottom>
Avanceret
</Typography>
<Chip label="Erfarne" color="warning" size="small" sx={{ mb: 1 }} />
<Typography variant="body2" color="textSecondary">
Fuld kontrol med alle felter og indstillinger
</Typography>
<Typography variant="caption" display="block" sx={{ mt: 2, color: 'warning.main' }}>
✓ Alle funktioner
<br />
✓ Fuld tilpasning
<br />
✓ Kræver erfaring
</Typography>
</Box>
</CardContent>
</Card>
</Grid>
</Grid>
</RadioGroup>
{/* Template Selection */}
{selectedMode === 'template' && templates && templates.length > 0 && (
<Box sx={{ mt: 3 }}>
<Typography variant="subtitle2" gutterBottom>
Vælg en skabelon:
</Typography>
<Grid container spacing={2}>
{templates.map(template => (
<Grid item xs={12} sm={6} key={template.id}>
<Card
variant="outlined"
sx={{
cursor: 'pointer',
border: selectedTemplate?.id === template.id ? 2 : 1,
borderColor: selectedTemplate?.id === template.id ? 'primary.main' : 'divider',
'&:hover': { borderColor: 'primary.main' }
}}
onClick={() => setSelectedTemplate(template)}
>
<CardContent>
<Typography variant="subtitle1" gutterBottom>
{template.name}
</Typography>
<Typography variant="body2" color="textSecondary" gutterBottom>
{template.description}
</Typography>
<Box sx={{ display: 'flex', gap: 1, mt: 1 }}>
<Chip label={template.category} size="small" />
<Chip label={`${template.materials?.length || 0} materialer`} size="small" variant="outlined" />
<Chip label={`${template.tasks?.length || 0} opgaver`} size="small" variant="outlined" />
</Box>
</CardContent>
</Card>
</Grid>
))}
</Grid>
</Box>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
Annuller
</Button>
<Button
variant="contained"
onClick={handleStart}
disabled={selectedMode === 'template' && !selectedTemplate}
>
Kom i gang
</Button>
</DialogActions>
</Dialog>
);
};
export default QuickStartDialog;