Files
rxminder/components/modals/EditReminderModal.tsx
William Valentin e48adbcb00 Initial commit: Complete NodeJS-native setup
- Migrated from Python pre-commit to NodeJS-native solution
- Reorganized documentation structure
- Set up Husky + lint-staged for efficient pre-commit hooks
- Fixed Dockerfile healthcheck issue
- Added comprehensive documentation index
2025-09-06 01:42:48 -07:00

196 lines
7.5 KiB
TypeScript

import React, { useState, useEffect, useRef } from 'react';
import { CustomReminder } from '../../types';
import { reminderIcons } from '../icons/Icons';
interface EditReminderModalProps {
isOpen: boolean;
onClose: () => void;
reminder: CustomReminder | null;
onUpdate: (reminder: CustomReminder) => Promise<void>;
}
const EditReminderModal: React.FC<EditReminderModalProps> = ({
isOpen,
onClose,
reminder,
onUpdate,
}) => {
const [title, setTitle] = useState('');
const [icon, setIcon] = useState('bell');
const [frequencyMinutes, setFrequencyMinutes] = useState(60);
const [startTime, setStartTime] = useState('09:00');
const [endTime, setEndTime] = useState('17:00');
const [isSaving, setIsSaving] = useState(false);
const titleInputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
if (isOpen && reminder) {
setTitle(reminder.title);
setIcon(reminder.icon);
setFrequencyMinutes(reminder.frequencyMinutes);
setStartTime(reminder.startTime);
setEndTime(reminder.endTime);
setIsSaving(false);
setTimeout(() => titleInputRef.current?.focus(), 100);
}
}, [isOpen, reminder]);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!title || !reminder || isSaving) return;
setIsSaving(true);
try {
await onUpdate({
...reminder,
title,
icon,
frequencyMinutes,
startTime,
endTime,
});
} catch (error) {
console.error('Failed to update reminder', error);
alert('There was an error updating your reminder. Please try again.');
} finally {
setIsSaving(false);
}
};
if (!isOpen) return null;
return (
<div
className='fixed inset-0 bg-black bg-opacity-50 dark:bg-opacity-70 z-50 flex justify-center items-center p-4'
role='dialog'
aria-modal='true'
aria-labelledby='edit-rem-title'
>
<div className='bg-white dark:bg-slate-800 rounded-lg shadow-xl w-full max-w-md'>
<div className='p-6 border-b border-slate-200 dark:border-slate-700'>
<h3
id='edit-rem-title'
className='text-xl font-semibold text-slate-800 dark:text-slate-100'
>
Edit Reminder
</h3>
</div>
<form onSubmit={handleSubmit}>
<div className='p-6 space-y-4 max-h-[70vh] overflow-y-auto'>
<div>
<label
htmlFor='rem-edit-title'
className='block text-sm font-medium text-slate-700 dark:text-slate-300'
>
Title
</label>
<input
type='text'
id='rem-edit-title'
value={title}
onChange={e => setTitle(e.target.value)}
required
ref={titleInputRef}
className='mt-1 block w-full px-3 py-2 border border-slate-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm bg-white dark:bg-slate-700 dark:border-slate-600 dark:placeholder-slate-400 dark:text-white'
/>
</div>
<div>
<label className='block text-sm font-medium text-slate-700 dark:text-slate-300'>
Icon
</label>
<div className='mt-2 flex flex-wrap gap-2'>
{Object.entries(reminderIcons).map(([key, IconComponent]) => (
<button
key={key}
type='button'
onClick={() => setIcon(key)}
className={`p-2 rounded-full transition-colors ${icon === key ? 'bg-indigo-600 text-white ring-2 ring-offset-2 ring-indigo-500 ring-offset-white dark:ring-offset-slate-800' : 'bg-slate-100 text-slate-600 hover:bg-slate-200 dark:bg-slate-700 dark:text-slate-300 dark:hover:bg-slate-600'}`}
aria-label={`Select ${key} icon`}
>
<IconComponent className='w-6 h-6' />
</button>
))}
</div>
</div>
<div>
<label
htmlFor='rem-edit-frequency'
className='block text-sm font-medium text-slate-700 dark:text-slate-300'
>
Remind me every (minutes)
</label>
<input
type='number'
id='rem-edit-frequency'
value={frequencyMinutes}
onChange={e =>
setFrequencyMinutes(parseInt(e.target.value, 10))
}
min='1'
className='mt-1 block w-full px-3 py-2 border border-slate-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm bg-white dark:bg-slate-700 dark:border-slate-600'
/>
</div>
<div className='grid grid-cols-2 gap-4'>
<div>
<label
htmlFor='rem-edit-startTime'
className='block text-sm font-medium text-slate-700 dark:text-slate-300'
>
From
</label>
<input
type='time'
id='rem-edit-startTime'
value={startTime}
onChange={e => setStartTime(e.target.value)}
required
className='mt-1 block w-full px-3 py-2 border border-slate-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm bg-white dark:bg-slate-700 dark:border-slate-600'
/>
</div>
<div>
<label
htmlFor='rem-edit-endTime'
className='block text-sm font-medium text-slate-700 dark:text-slate-300'
>
Until
</label>
<input
type='time'
id='rem-edit-endTime'
value={endTime}
onChange={e => setEndTime(e.target.value)}
required
className='mt-1 block w-full px-3 py-2 border border-slate-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm bg-white dark:bg-slate-700 dark:border-slate-600'
/>
</div>
</div>
</div>
<div className='px-6 py-4 bg-slate-50 dark:bg-slate-700/50 flex justify-end space-x-3 rounded-b-lg border-t border-slate-200 dark:border-slate-700'>
<button
type='button'
onClick={onClose}
disabled={isSaving}
className='px-4 py-2 text-sm font-medium text-slate-700 bg-white border border-slate-300 rounded-md shadow-sm hover:bg-slate-50 disabled:opacity-50 dark:bg-slate-700 dark:text-slate-200 dark:border-slate-600 dark:hover:bg-slate-600'
>
Cancel
</button>
<button
type='submit'
disabled={isSaving}
className='px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed flex items-center dark:focus:ring-offset-slate-800'
>
{isSaving ? 'Saving...' : 'Save Changes'}
</button>
</div>
</form>
</div>
</div>
);
};
export default EditReminderModal;