950f51c61b
Success overlay with animated checkmark and 'Dein Tipp ist drin! 🎯' message. Haptic vibration on mobile. Auto-closes after 1.2s. - Add showSuccess state to TipModal - Trigger vibration feedback on successful submit - Display success overlay with popIn animation for checkmark - Auto-close modal after success animation completes - Add CSS animations (fadeIn, popIn) to TipModal.module.css Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
54 lines
4.6 KiB
JavaScript
54 lines
4.6 KiB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
import { useState } from 'react';
|
|
import { api } from '../api/client';
|
|
import styles from './TipModal.module.css';
|
|
function getTendency(home, away) {
|
|
if (home > away)
|
|
return 'home';
|
|
if (away > home)
|
|
return 'away';
|
|
return 'draw';
|
|
}
|
|
export default function TipModal({ match, onClose, onSaved }) {
|
|
const existing = match.userTip;
|
|
const [home, setHome] = useState(existing?.home ?? 0);
|
|
const [away, setAway] = useState(existing?.away ?? 0);
|
|
const [saving, setSaving] = useState(false);
|
|
const [showSuccess, setShowSuccess] = useState(false);
|
|
const [error, setError] = useState(null);
|
|
const tendency = getTendency(home, away);
|
|
const tendencyLabel = tendency === 'home' ? match.homeTeam.shortName || match.homeTeam.name :
|
|
tendency === 'away' ? match.awayTeam.shortName || match.awayTeam.name :
|
|
'Unentschieden';
|
|
const tendencyColor = tendency === 'home' ? 'var(--primary)' :
|
|
tendency === 'away' ? 'var(--cyan)' :
|
|
'var(--gold)';
|
|
const handleSave = async () => {
|
|
setSaving(true);
|
|
setError(null);
|
|
try {
|
|
await api.submitTip(match.id, home, away);
|
|
setShowSuccess(true);
|
|
if (navigator.vibrate)
|
|
navigator.vibrate(50); // haptic feedback
|
|
setTimeout(() => {
|
|
setShowSuccess(false);
|
|
onSaved(match.id, home, away);
|
|
onClose();
|
|
}, 1200);
|
|
}
|
|
catch (e) {
|
|
setError(e.message);
|
|
setSaving(false);
|
|
}
|
|
};
|
|
return (_jsx("div", { className: styles.overlay, onClick: onClose, children: _jsxs("div", { className: styles.sheet, onClick: e => e.stopPropagation(), children: [_jsx("div", { className: styles.handle }), _jsxs("div", { className: styles.teamsRow, children: [_jsxs("div", { className: styles.teamBlock, children: [_jsx("div", { className: styles.flagLarge, children: match.homeTeam.crest
|
|
? _jsx("img", { src: match.homeTeam.crest, alt: match.homeTeam.name, className: styles.flagImg })
|
|
: _jsx("span", { className: styles.flagEmoji, children: "\uD83C\uDFF3\uFE0F" }) }), _jsx("span", { className: styles.teamName, children: match.homeTeam.name })] }), _jsx("div", { className: styles.vsBlock }), _jsxs("div", { className: styles.teamBlock, children: [_jsx("div", { className: styles.flagLarge, children: match.awayTeam.crest
|
|
? _jsx("img", { src: match.awayTeam.crest, alt: match.awayTeam.name, className: styles.flagImg })
|
|
: _jsx("span", { className: styles.flagEmoji, children: "\uD83C\uDFF3\uFE0F" }) }), _jsx("span", { className: styles.teamName, children: match.awayTeam.name })] })] }), _jsxs("div", { className: styles.pickerSection, children: [_jsx("p", { className: styles.pickerLabel, children: "Dein Tipp" }), _jsxs("div", { className: styles.pickerRow, children: [_jsx(ScorePicker, { value: home, onChange: setHome }), _jsx("div", { className: styles.pickerColon, children: ":" }), _jsx(ScorePicker, { value: away, onChange: setAway })] })] }), _jsxs("div", { className: styles.tendencyBar, style: { '--tendency-color': tendencyColor }, children: [_jsx("span", { className: styles.tendencyIcon, children: tendency === 'draw' ? '🤝' : tendency === 'home' ? '🏠' : '✈️' }), _jsxs("span", { className: styles.tendencyText, children: ["Tendenz: ", _jsx("strong", { children: tendencyLabel })] })] }), error && _jsx("div", { className: styles.error, children: error }), showSuccess && (_jsxs("div", { className: styles.successOverlay, children: [_jsx("div", { className: styles.successCheck, children: "\u2713" }), _jsx("div", { className: styles.successText, children: "Dein Tipp ist drin! \uD83C\uDFAF" })] })), _jsx("button", { className: `btn-primary ${styles.saveBtn}`, onClick: handleSave, disabled: saving, children: saving ? '⏳ Wird gespeichert…' : '✓ Tipp bestätigen' }), _jsx("button", { className: styles.cancelBtn, onClick: onClose, children: "Abbrechen" })] }) }));
|
|
}
|
|
function ScorePicker({ value, onChange }) {
|
|
return (_jsxs("div", { className: styles.picker, children: [_jsx("button", { className: styles.pickerBtn, onClick: () => onChange(Math.min(20, value + 1)), "aria-label": "Erh\u00F6hen", children: "+" }), _jsx("span", { className: styles.pickerValue, children: value }), _jsx("button", { className: styles.pickerBtn, onClick: () => onChange(Math.max(0, value - 1)), "aria-label": "Verringern", children: "\u2212" })] }));
|
|
}
|