My-Weekly-ToDo-List/src/components/ImportListModal.tsx
mARTin 798bcfe44a feat: Add Google Tasks, Apple Reminders, task import/sync, holidays, and UI enhancements
- Add Google Tasks integration and Apple Reminders support
- Add task import/export with list management APIs
- Add goal API for weekly goals
- Add German holidays library
- Add ImportListModal component
- Enhance WeeklyView with major UI improvements
- Enhance CalendarSettings with new connection options
- Add external task fields to database schema
- Add Playwright test suites for auth and tasks
- Add iCloud reminders Python scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 16:56:14 +01:00

163 lines
6.5 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { X, Check, Loader } from 'lucide-react';
interface ImportListModalProps {
isOpen: boolean;
onClose: () => void;
onImport: (selectedLists: { id: string, title: string }[]) => void;
provider: 'google' | 'apple' | null;
lists: { id: string, title: string }[];
isLoading: boolean;
}
export const ImportListModal: React.FC<ImportListModalProps> = ({
isOpen,
onClose,
onImport,
provider,
lists,
isLoading
}) => {
const [selectedIds, setSelectedIds] = useState<string[]>([]);
// Reset selection when opening
useEffect(() => {
if (isOpen) {
setSelectedIds([]);
}
}, [isOpen]);
if (!isOpen) return null;
const toggleSelection = (id: string) => {
if (selectedIds.includes(id)) {
setSelectedIds(selectedIds.filter(lid => lid !== id));
} else {
setSelectedIds([...selectedIds, id]);
}
};
const handleSelectAll = () => {
if (selectedIds.length === lists.length) {
setSelectedIds([]);
} else {
setSelectedIds(lists.map(l => l.id));
}
};
return (
<div style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: 1000
}}>
<div style={{
background: 'white',
padding: '2rem',
borderRadius: '8px',
width: '100%',
maxWidth: '500px',
maxHeight: '80vh',
display: 'flex',
flexDirection: 'column',
gap: '1rem',
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)'
}}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<h2 style={{ fontSize: '1.25rem', fontWeight: 600 }}>
Import from {provider === 'google' ? 'Google Tasks' : 'Apple Reminders'}
</h2>
<button onClick={onClose} className="p-1 hover:bg-gray-100 rounded-full">
<X size={20} />
</button>
</div>
<div style={{ flex: 1, overflowY: 'auto', minHeight: '200px' }}>
{isLoading ? (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
<Loader className="animate-spin" />
<span style={{ marginLeft: '8px' }}>Loading lists...</span>
</div>
) : lists.length === 0 ? (
<p style={{ textAlign: 'center', color: '#666', marginTop: '2rem' }}>
No task lists found.
</p>
) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: '8px' }}>
<button
onClick={handleSelectAll}
style={{ fontSize: '0.875rem', color: '#3b82f6', background: 'none', border: 'none', cursor: 'pointer' }}
>
{selectedIds.length === lists.length ? 'Deselect All' : 'Select All'}
</button>
</div>
{lists.map(list => (
<label
key={list.id}
style={{
display: 'flex',
alignItems: 'center',
gap: '10px',
padding: '8px',
borderRadius: '4px',
cursor: 'pointer',
backgroundColor: selectedIds.includes(list.id) ? '#eff6ff' : 'transparent'
}}
>
<input
type="checkbox"
checked={selectedIds.includes(list.id)}
onChange={() => toggleSelection(list.id)}
style={{ width: '16px', height: '16px' }}
/>
<span>{list.title}</span>
</label>
))}
</div>
)}
</div>
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '1rem', marginTop: '1rem' }}>
<button
onClick={onClose}
style={{
padding: '8px 16px',
borderRadius: '4px',
border: '1px solid #e5e7eb',
background: 'white',
cursor: 'pointer'
}}
>
Cancel
</button>
<button
onClick={() => onImport(lists.filter(l => selectedIds.includes(l.id)))}
disabled={selectedIds.length === 0 || isLoading}
style={{
padding: '8px 16px',
borderRadius: '4px',
background: selectedIds.length === 0 || isLoading ? '#9ca3af' : '#2563eb',
color: 'white',
border: 'none',
cursor: selectedIds.length === 0 || isLoading ? 'not-allowed' : 'pointer',
display: 'flex',
alignItems: 'center',
gap: '8px'
}}
>
{isLoading ? 'Importing...' : 'Import Selected'}
</button>
</div>
</div>
</div>
);
};