fix(todo): resolve type errors and update component props

- Fix KanbanColumn to use DndEvent type from svelte-dnd-action
- Extend UpdateTaskDto and store updateTask method to support all task fields
- Add metadata type cast in +page.svelte for compatibility
- Create feedback service and update FeedbackPage to use new API
- Fix forgot-password page: rename handler to onForgotPassword, use titleForm
- Remove deprecated enableGoogle/enableApple props from RegisterPage

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Till-JS 2025-12-10 20:16:17 +01:00
parent 0b28eba3f2
commit 812a6f5090
8 changed files with 69 additions and 40 deletions

View file

@ -14,13 +14,21 @@ interface CreateTaskDto {
interface UpdateTaskDto {
title?: string;
description?: string;
description?: string | null;
projectId?: string | null;
parentTaskId?: string | null;
dueDate?: string | null;
dueTime?: string | null;
startDate?: string | null;
priority?: TaskPriority;
status?: TaskStatus;
subtasks?: Subtask[];
isCompleted?: boolean;
order?: number;
subtasks?: Subtask[] | null;
recurrenceRule?: string | null;
recurrenceEndDate?: string | null;
metadata?: Record<string, unknown> | null;
labelIds?: string[];
}
interface TaskQuery {

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { dndzone, SHADOW_PLACEHOLDER_ITEM_ID } from 'svelte-dnd-action';
import type { KanbanColumn, Task, UpdateTaskInput } from '@todo/shared';
import { dndzone, SHADOW_PLACEHOLDER_ITEM_ID, type DndEvent } from 'svelte-dnd-action';
import type { KanbanColumn, Task } from '@todo/shared';
import KanbanTaskCard from './KanbanTaskCard.svelte';
import KanbanColumnHeader from './KanbanColumnHeader.svelte';
import QuickAddTaskInline from './QuickAddTaskInline.svelte';
@ -36,13 +36,11 @@
const flipDurationMs = 200;
function handleDndConsider(e: CustomEvent<{ items: Task[] }>) {
function handleDndConsider(e: CustomEvent<DndEvent<Task>>) {
localTasks = e.detail.items;
}
function handleDndFinalize(
e: CustomEvent<{ items: Task[]; info: { id: string; source: { items: Task[] } } }>
) {
function handleDndFinalize(e: CustomEvent<DndEvent<Task>>) {
const newItems = e.detail.items.filter((t) => t.id !== SHADOW_PLACEHOLDER_ITEM_ID);
const movedTaskId = e.detail.info.id;
@ -71,20 +69,21 @@
}
}
async function handleSaveTask(task: Task, data: UpdateTaskInput) {
// Transform data to match updateTask API (convert null to undefined)
const updateData: UpdateTaskInput = {};
async function handleSaveTask(task: Task, data: Partial<Task>) {
// Transform Partial<Task> to updateTask format
const updateData: Record<string, unknown> = {};
if (data.title !== undefined) updateData.title = data.title;
if (data.description !== undefined) updateData.description = data.description ?? undefined;
if (data.description !== undefined) updateData.description = data.description;
if (data.projectId !== undefined) updateData.projectId = data.projectId;
if (data.dueDate !== undefined) updateData.dueDate = data.dueDate ?? undefined;
if (data.dueDate !== undefined) {
updateData.dueDate = data.dueDate instanceof Date ? data.dueDate.toISOString() : data.dueDate;
}
if (data.priority !== undefined) updateData.priority = data.priority;
if (data.status !== undefined) updateData.status = data.status;
if (data.subtasks !== undefined) updateData.subtasks = data.subtasks ?? undefined;
if (data.recurrenceRule !== undefined)
updateData.recurrenceRule = data.recurrenceRule ?? undefined;
if (data.subtasks !== undefined) updateData.subtasks = data.subtasks;
if (data.recurrenceRule !== undefined) updateData.recurrenceRule = data.recurrenceRule;
if (data.metadata !== undefined) updateData.metadata = data.metadata;
if (data.labelIds !== undefined) updateData.labelIds = data.labelIds;
if (data.labels !== undefined) updateData.labelIds = data.labels?.map((l) => l.id);
await tasksStore.updateTask(task.id, updateData);
}

View file

@ -0,0 +1,23 @@
/**
* Feedback Service Instance for Todo Web App
*/
import { browser } from '$app/environment';
import { createFeedbackService } from '@manacore/shared-feedback-service';
import { authStore } from '$lib/stores/auth.svelte';
// Get auth URL dynamically at runtime
function getAuthUrl(): string {
if (browser && typeof window !== 'undefined') {
const injectedUrl = (window as unknown as { __PUBLIC_MANA_CORE_AUTH_URL__?: string })
.__PUBLIC_MANA_CORE_AUTH_URL__;
return injectedUrl || 'http://localhost:3001';
}
return 'http://localhost:3001';
}
export const feedbackService = createFeedbackService({
apiUrl: getAuthUrl(),
appId: 'todo',
getAuthToken: async () => authStore.getAccessToken(),
});

View file

@ -217,13 +217,21 @@ export const tasksStore = {
id: string,
data: {
title?: string;
description?: string;
description?: string | null;
projectId?: string | null;
parentTaskId?: string | null;
dueDate?: string | null;
dueTime?: string | null;
startDate?: string | null;
priority?: TaskPriority;
status?: TaskStatus;
subtasks?: Subtask[];
isCompleted?: boolean;
order?: number;
subtasks?: Subtask[] | null;
recurrenceRule?: string | null;
recurrenceEndDate?: string | null;
metadata?: { [key: string]: unknown } | null;
labelIds?: string[];
}
) {
error = null;

View file

@ -100,8 +100,12 @@
if (!editingTask) return;
try {
// Update task
await tasksStore.updateTask(editingTask.id, data);
// Update task - cast metadata to be compatible with store type
const updateData = {
...data,
metadata: data.metadata as { [key: string]: unknown } | null | undefined,
};
await tasksStore.updateTask(editingTask.id, updateData);
// Update labels if provided
if (data.labelIds !== undefined) {

View file

@ -1,22 +1,11 @@
<script lang="ts">
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { authStore } from '$lib/stores/auth.svelte';
import { FeedbackPage } from '@manacore/shared-feedback-ui';
onMount(() => {
if (!authStore.isAuthenticated) {
goto('/login');
}
});
import { feedbackService } from '$lib/services/feedback';
import { authStore } from '$lib/stores/auth.svelte';
</script>
<svelte:head>
<title>Feedback | Todo</title>
</svelte:head>
<FeedbackPage
appName="Todo"
userEmail={authStore.user?.email || undefined}
primaryColor="#8b5cf6"
/>
<FeedbackPage {feedbackService} appName="Todo" currentUserId={authStore.user?.id} />

View file

@ -11,20 +11,20 @@
// Get translations based on current locale
const translations = $derived(getForgotPasswordTranslations($locale || 'de'));
async function handleResetPassword(email: string) {
async function handleForgotPassword(email: string) {
return authStore.resetPassword(email);
}
</script>
<svelte:head>
<title>{translations.title} | Todo</title>
<title>{translations.titleForm} | Todo</title>
</svelte:head>
<ForgotPasswordPage
appName="Todo"
logo={TodoLogo}
primaryColor="#8b5cf6"
onResetPassword={handleResetPassword}
onForgotPassword={handleForgotPassword}
{goto}
loginPath="/login"
lightBackground="#f3e8ff"

View file

@ -26,8 +26,6 @@
primaryColor="#8b5cf6"
onSignUp={handleSignUp}
{goto}
enableGoogle={false}
enableApple={false}
successRedirect="/"
loginPath="/login"
lightBackground="#f3e8ff"