import { Action, useNavigation, ActionPanel, Form, Icon, getPreferenceValues, showToast, Toast } from "@raycast/api"; import { MutatePromise, useForm, FormValidation, useFetch } from "@raycast/utils"; import { Notification, isNotificationBuiltFromTask } from "../notification"; import { Page, UniversalInboxPreferences } from "../types"; import { default as dayjs, extend } from "dayjs"; import { TaskPriority } from "../task"; import { handleErrors } from "../api"; import utc from "dayjs/plugin/utc"; import { useState } from "react"; import fetch from "node-fetch"; extend(utc); interface PlanTaskProps { notification: Notification; mutate: MutatePromise | undefined>; } interface TaskPlanningFormValues { project: string; dueAt: Date | null; priority: string; } interface ProjectSummary { name: string; source_id: string; } interface TaskPlanning { project: ProjectSummary; due_at?: { type: "DateTimeWithTz"; content: string }; priority: TaskPriority; } export function PlanTask({ notification, mutate }: PlanTaskProps) { const preferences = getPreferenceValues(); const { pop } = useNavigation(); const [searchText, setSearchText] = useState(""); const { isLoading, data: projects } = useFetch>( `${preferences.universalInboxBaseUrl.replace(/\/$/, "")}/api/tasks/projects/search?matches=${searchText}`, { keepPreviousData: true, headers: { Authorization: `Bearer ${preferences.apiKey}`, }, }, ); const { handleSubmit, itemProps } = useForm({ initialValues: { dueAt: new Date(), project: projects?.find((p) => p.name === "Inbox")?.source_id, priority: `${TaskPriority.P4 as number}`, }, async onSubmit(values) { const project = projects?.find((p) => p.source_id === values.project); if (!project) { throw new Error("Project not found"); } const taskPlanning: TaskPlanning = { project: project, due_at: values.dueAt ? { type: "DateTimeWithTz", content: dayjs(values.dueAt).utc().format() } : undefined, priority: parseInt(values.priority) as TaskPriority, }; await planTask(taskPlanning, notification, mutate); pop(); }, validation: { project: FormValidation.Required, priority: FormValidation.Required, }, }); return (
} > {projects?.map((project) => { return ; })} ); } async function planTask( taskPlanning: TaskPlanning, notification: Notification, mutate: MutatePromise | undefined>, ) { if (!isNotificationBuiltFromTask(notification) || !notification.task) { return; } const preferences = getPreferenceValues(); const toast = await showToast({ style: Toast.Style.Animated, title: "Planning task" }); try { await mutate( handleErrors( fetch(`${preferences.universalInboxBaseUrl.replace(/\/$/, "")}/api/tasks/${notification.task.id}`, { method: "PATCH", body: JSON.stringify({ project: taskPlanning.project.name, due_at: taskPlanning.due_at, priority: taskPlanning.priority, }), headers: { "Content-Type": "application/json", Authorization: `Bearer ${preferences.apiKey}`, }, }), ), { optimisticUpdate(page) { if (page) { page.content = page.content.filter((n) => n.id !== notification.id); } return page; }, }, ); toast.style = Toast.Style.Success; toast.title = "Task successfully planned"; } catch (error) { toast.style = Toast.Style.Failure; toast.title = "Failed to plan task"; toast.message = (error as Error).message; throw error; } }