1851d2ed47
Add TimeToLeave feature checklist and plan
166 lines
5.0 KiB
TypeScript
166 lines
5.0 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState, useEffect } from "react";
|
|
import Button from "@/app/ui/Button";
|
|
import { useEventsStore } from "@/hooks/useEventsStore";
|
|
|
|
type AddEventModalProps = {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
className?: string;
|
|
};
|
|
|
|
const AddEventModal: React.FC<AddEventModalProps> = ({ isOpen, onClose, className = "" }) => {
|
|
const [title, setTitle] = useState("");
|
|
const [destination, setDestination] = useState("");
|
|
const [eventTime, setEventTime] = useState("");
|
|
const [eventDate, setEventDate] = useState("");
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const { addEvent } = useEventsStore();
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (!title.trim() || !destination.trim() || !eventTime.trim() || !eventDate.trim()) {
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
try {
|
|
const eventTimeDate = new Date(`${eventDate} ${eventTime}`);
|
|
|
|
await addEvent({
|
|
id: `manual-${Date.now()}`,
|
|
title: title.trim(),
|
|
destination: destination.trim(),
|
|
eventTime: eventTimeDate,
|
|
source: "manual",
|
|
});
|
|
|
|
// Reset form and close modal
|
|
setTitle("");
|
|
setDestination("");
|
|
setEventTime("");
|
|
setEventDate("");
|
|
onClose();
|
|
} catch (err) {
|
|
console.error("Error adding event:", err);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
// Close modal when clicking outside
|
|
const handleBackdropClick = (e: React.MouseEvent) => {
|
|
if (e.target === e.currentTarget) {
|
|
onClose();
|
|
}
|
|
};
|
|
|
|
// Close modal with Escape key
|
|
useEffect(() => {
|
|
const handleEscape = (e: KeyboardEvent) => {
|
|
if (e.key === "Escape") {
|
|
onClose();
|
|
}
|
|
};
|
|
|
|
if (isOpen) {
|
|
document.addEventListener("keydown", handleEscape);
|
|
}
|
|
|
|
return () => {
|
|
document.removeEventListener("keydown", handleEscape);
|
|
};
|
|
}, [isOpen, onClose]);
|
|
|
|
if (!isOpen) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4 backdrop-blur-sm"
|
|
onClick={handleBackdropClick}
|
|
>
|
|
<div className={`brand-panel w-full max-w-md rounded-2xl ${className}`}>
|
|
<div className="p-6">
|
|
<p className="mb-2 text-xs font-semibold uppercase tracking-[0.24em] text-[#D946EF]">Manual event</p>
|
|
<h3 className="mb-6 text-2xl font-bold text-white">Add a departure target</h3>
|
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
<div>
|
|
<label htmlFor="event-title" className="mb-1 block text-sm font-medium text-[#F4F1EA]/76">
|
|
Event Title
|
|
</label>
|
|
<input
|
|
id="event-title"
|
|
type="text"
|
|
value={title}
|
|
onChange={(e) => setTitle(e.target.value)}
|
|
placeholder="Team Meeting"
|
|
className="brand-input px-3 py-2"
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
htmlFor="event-destination"
|
|
className="mb-1 block text-sm font-medium text-[#F4F1EA]/76"
|
|
>
|
|
Destination
|
|
</label>
|
|
<input
|
|
id="event-destination"
|
|
type="text"
|
|
value={destination}
|
|
onChange={(e) => setDestination(e.target.value)}
|
|
placeholder="Vienna Main Station"
|
|
className="brand-input px-3 py-2"
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label htmlFor="event-date" className="mb-1 block text-sm font-medium text-[#F4F1EA]/76">
|
|
Date
|
|
</label>
|
|
<input
|
|
id="event-date"
|
|
type="date"
|
|
value={eventDate}
|
|
onChange={(e) => setEventDate(e.target.value)}
|
|
className="brand-input px-3 py-2"
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label htmlFor="event-time" className="mb-1 block text-sm font-medium text-[#F4F1EA]/76">
|
|
Time
|
|
</label>
|
|
<input
|
|
id="event-time"
|
|
type="time"
|
|
value={eventTime}
|
|
onChange={(e) => setEventTime(e.target.value)}
|
|
className="brand-input px-3 py-2"
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="flex justify-end space-x-3 mt-6">
|
|
<Button type="button" variant="secondary" onClick={onClose}>
|
|
Cancel
|
|
</Button>
|
|
<Button type="submit" disabled={loading}>
|
|
{loading ? <>Add Event</> : <>Add Event</>}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default AddEventModal;
|