refactor habit creation form to support both creation and editing
This commit is contained in:
@@ -94,7 +94,7 @@
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content class="sm:max-w-lg">
|
||||
<HabitCreationForm
|
||||
onHabitCreated={() => {
|
||||
onComplete={() => {
|
||||
showCreateDialog = false;
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
<script lang="ts">
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index.js';
|
||||
import { Button, buttonVariants } from '$lib/components/ui/button/index.js';
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import { EllipsisVertical, Pencil, Trash2 } from '@lucide/svelte';
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog/index.js';
|
||||
import * as Dialog from '$lib/components/ui/dialog/index.js';
|
||||
import { Input } from '$lib/components/ui/input/index.js';
|
||||
import { Label } from '$lib/components/ui/label/index.js';
|
||||
import { getHabitService } from '$lib/context/habits.svelte';
|
||||
import HabitCreationForm from './HabitCreationForm.svelte';
|
||||
|
||||
const habitService = getHabitService();
|
||||
|
||||
let { habitId } = $props();
|
||||
let { habitId }: { habitId: string } = $props();
|
||||
|
||||
// Get the current habit reactively from the service
|
||||
const currentHabit = $derived(habitService.habits.find(h => h.id === habitId));
|
||||
const currentHabit = $derived(habitService.habits.find((h) => h.id === habitId));
|
||||
|
||||
let deleteHabitDialog = $state(false);
|
||||
let editHabitDialog = $state(false);
|
||||
|
||||
</script>
|
||||
|
||||
<DropdownMenu.Root>
|
||||
@@ -47,26 +45,10 @@
|
||||
|
||||
<!-- Edit Habit Dialog -->
|
||||
<Dialog.Root bind:open={editHabitDialog}>
|
||||
<Dialog.Content class="sm:max-w-110">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Edit profile</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Make changes to your profile here. Click save when you're done.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
<div class="grid gap-4 py-4">
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="name" class="text-right">Name</Label>
|
||||
<Input id="name" value="Pedro Duarte" class="col-span-3" />
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="username" class="text-right">Username</Label>
|
||||
<Input id="username" value="@peduarte" class="col-span-3" />
|
||||
</div>
|
||||
</div>
|
||||
<Dialog.Footer>
|
||||
<Button type="submit">Save changes</Button>
|
||||
</Dialog.Footer>
|
||||
<Dialog.Content class="sm:max-w-lg">
|
||||
{#if currentHabit}
|
||||
<HabitCreationForm habit={currentHabit} onComplete={() => { editHabitDialog = false; }} />
|
||||
{/if}
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
|
||||
@@ -7,23 +7,48 @@
|
||||
import * as Collapsible from '$lib/components/ui/collapsible';
|
||||
import { ChevronDown, ChevronUp } from '@lucide/svelte';
|
||||
import { getHabitService } from '$lib/context/habits.svelte';
|
||||
import type { Habit } from '$lib/triplit/schema';
|
||||
|
||||
let { onHabitCreated }: { onHabitCreated?: () => Promise<void> | void } = $props();
|
||||
let {
|
||||
habit,
|
||||
onComplete
|
||||
}: {
|
||||
habit?: Habit;
|
||||
onComplete?: () => Promise<void> | void;
|
||||
} = $props();
|
||||
|
||||
const habitService = getHabitService();
|
||||
|
||||
const isEditMode = $derived(!!habit);
|
||||
|
||||
let showAdvancedOptions = $state(false);
|
||||
let isSubmitting = $state(false);
|
||||
|
||||
// Form fields
|
||||
let name = $state('');
|
||||
let target = $state(1);
|
||||
let duration = $state(1);
|
||||
let unit = $state('');
|
||||
let increment = $state(1);
|
||||
let startDate = $state(new Date().toISOString().split('T')[0]);
|
||||
let active = $state(true);
|
||||
// Form fields - initialize from habit if editing
|
||||
let name = $state(habit?.name ?? '');
|
||||
let target = $state(habit?.target ?? 1);
|
||||
let duration = $state(habit?.duration ?? 1);
|
||||
let unit = $state(habit?.unit ?? '');
|
||||
let increment = $state(habit?.increment ?? 1);
|
||||
let startDate = $state(
|
||||
habit?.startDate
|
||||
? habit.startDate.toISOString().split('T')[0]
|
||||
: new Date().toISOString().split('T')[0]
|
||||
);
|
||||
let active = $state(habit?.active ?? true);
|
||||
|
||||
// Re-initialize when habit changes (for edit mode)
|
||||
$effect(() => {
|
||||
if (habit) {
|
||||
name = habit.name;
|
||||
target = habit.target;
|
||||
duration = habit.duration;
|
||||
unit = habit.unit;
|
||||
increment = habit.increment;
|
||||
startDate = habit.startDate.toISOString().split('T')[0];
|
||||
active = habit.active;
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
if (isSubmitting || !name.trim()) return;
|
||||
@@ -31,34 +56,37 @@
|
||||
try {
|
||||
isSubmitting = true;
|
||||
|
||||
await habitService.createHabit({
|
||||
const habitData = {
|
||||
name,
|
||||
target,
|
||||
duration,
|
||||
increment,
|
||||
unit,
|
||||
startDate: (() => {
|
||||
// Create date in local timezone to avoid UTC conversion issues
|
||||
const [year, month, day] = startDate.split('-').map(Number);
|
||||
return new Date(year, month - 1, day);
|
||||
})(),
|
||||
active
|
||||
})
|
||||
};
|
||||
|
||||
// Reset form
|
||||
name = '';
|
||||
target = 1;
|
||||
duration = 1;
|
||||
unit = '';
|
||||
increment = 1;
|
||||
startDate = new Date().toISOString().split('T')[0];
|
||||
active = true;
|
||||
showAdvancedOptions = false;
|
||||
if (isEditMode && habit) {
|
||||
await habitService.updateHabit(habit.id, habitData);
|
||||
} else {
|
||||
await habitService.createHabit(habitData);
|
||||
// Reset form only for create mode
|
||||
name = '';
|
||||
target = 1;
|
||||
duration = 1;
|
||||
unit = '';
|
||||
increment = 1;
|
||||
startDate = new Date().toISOString().split('T')[0];
|
||||
active = true;
|
||||
showAdvancedOptions = false;
|
||||
}
|
||||
|
||||
// Notify parent
|
||||
onHabitCreated?.();
|
||||
onComplete?.();
|
||||
} catch (error) {
|
||||
console.error('Failed to create habit:', error);
|
||||
console.error(`Failed to ${isEditMode ? 'update' : 'create'} habit:`, error);
|
||||
} finally {
|
||||
isSubmitting = false;
|
||||
}
|
||||
@@ -66,9 +94,11 @@
|
||||
</script>
|
||||
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Create a new habit</Dialog.Title>
|
||||
<Dialog.Title>{isEditMode ? 'Edit habit' : 'Create a new habit'}</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Add a new habit to track. Set your target and customize the tracking period.
|
||||
{isEditMode
|
||||
? 'Update your habit settings. Click save when you\'re done.'
|
||||
: 'Add a new habit to track. Set your target and customize the tracking period.'}
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
@@ -223,9 +253,9 @@
|
||||
class="gap-2"
|
||||
>
|
||||
{#if isSubmitting}
|
||||
Creating...
|
||||
{isEditMode ? 'Saving...' : 'Creating...'}
|
||||
{:else}
|
||||
Create Habit
|
||||
{isEditMode ? 'Save Changes' : 'Create Habit'}
|
||||
{/if}
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
|
||||
Reference in New Issue
Block a user