build: 55712324-398e-4334-a254-fc30c84b2e47
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
IonButton,
|
||||
IonButtons,
|
||||
IonContent,
|
||||
IonHeader,
|
||||
IonInput,
|
||||
IonItem,
|
||||
IonLabel,
|
||||
IonModal,
|
||||
IonTextarea,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
} from '@ionic/react';
|
||||
|
||||
interface HabitFormModalProps {
|
||||
isOpen: boolean;
|
||||
onDismiss: () => void;
|
||||
onSubmit: (values: {
|
||||
name: string;
|
||||
targetDescription: string;
|
||||
color: string;
|
||||
}) => Promise<void>;
|
||||
initialValues?: {
|
||||
name: string;
|
||||
targetDescription: string;
|
||||
color: string;
|
||||
};
|
||||
}
|
||||
|
||||
const COLORS = [
|
||||
'#7c3aed',
|
||||
'#0f766e',
|
||||
'#ea580c',
|
||||
'#dc2626',
|
||||
'#2563eb',
|
||||
'#059669',
|
||||
];
|
||||
|
||||
const HabitFormModal: React.FC<HabitFormModalProps> = ({
|
||||
isOpen,
|
||||
onDismiss,
|
||||
onSubmit,
|
||||
initialValues,
|
||||
}) => {
|
||||
const isEditing = !!initialValues;
|
||||
const [name, setName] = useState(initialValues?.name ?? '');
|
||||
const [targetDescription, setTargetDescription] = useState(
|
||||
initialValues?.targetDescription ?? ''
|
||||
);
|
||||
const [color, setColor] = useState(initialValues?.color ?? COLORS[0]);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const canSubmit = useMemo(
|
||||
() => name.trim().length > 0 && name.trim().length <= 80,
|
||||
[name]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setName(initialValues?.name ?? '');
|
||||
setTargetDescription(initialValues?.targetDescription ?? '');
|
||||
setColor(initialValues?.color ?? COLORS[0]);
|
||||
setError('');
|
||||
}
|
||||
}, [isOpen, initialValues]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
setError('');
|
||||
setSaving(true);
|
||||
try {
|
||||
await onSubmit({
|
||||
name: name.trim(),
|
||||
targetDescription: targetDescription.trim(),
|
||||
color,
|
||||
});
|
||||
setName('');
|
||||
setTargetDescription('');
|
||||
setColor(COLORS[0]);
|
||||
onDismiss();
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Unable to save habit.');
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<IonModal isOpen={isOpen} onDidDismiss={onDismiss}>
|
||||
<IonHeader className="ion-no-border">
|
||||
<IonToolbar>
|
||||
<IonTitle>{isEditing ? 'Edit Habit' : 'New Habit'}</IonTitle>
|
||||
<IonButtons slot="end">
|
||||
<IonButton onClick={onDismiss}>Close</IonButton>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent className="ion-padding">
|
||||
<div className="habit-form-grid">
|
||||
<IonItem lines="none" className="auth-input-item">
|
||||
<IonInput
|
||||
label="Habit name"
|
||||
labelPlacement="stacked"
|
||||
value={name}
|
||||
maxlength={80}
|
||||
placeholder="Drink water"
|
||||
onIonInput={(e) => setName(e.detail.value ?? '')}
|
||||
/>
|
||||
</IonItem>
|
||||
|
||||
<IonItem lines="none" className="auth-input-item">
|
||||
<IonTextarea
|
||||
label="Target or note"
|
||||
labelPlacement="stacked"
|
||||
value={targetDescription}
|
||||
placeholder="8 glasses, 20 minutes, 30 pushups..."
|
||||
autoGrow
|
||||
onIonInput={(e) => setTargetDescription(e.detail.value ?? '')}
|
||||
/>
|
||||
</IonItem>
|
||||
|
||||
<div>
|
||||
<IonLabel className="color-label">Color</IonLabel>
|
||||
<div className="habit-color-row">
|
||||
{COLORS.map((swatch) => (
|
||||
<button
|
||||
key={swatch}
|
||||
type="button"
|
||||
className={`habit-color-dot ${color === swatch ? 'selected' : ''}`}
|
||||
style={{ background: swatch }}
|
||||
onClick={() => setColor(swatch)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error ? <p className="auth-feedback error-text">{error}</p> : null}
|
||||
|
||||
<IonButton
|
||||
expand="block"
|
||||
onClick={handleSubmit}
|
||||
disabled={!canSubmit || saving}
|
||||
>
|
||||
{saving ? 'Saving…' : isEditing ? 'Save Changes' : 'Create Habit'}
|
||||
</IonButton>
|
||||
</div>
|
||||
</IonContent>
|
||||
</IonModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default HabitFormModal;
|
||||
Reference in New Issue
Block a user