diff --git a/src/blitz-client.ts b/src/blitz-client.ts index db1b392d..33833cd8 100644 --- a/src/blitz-client.ts +++ b/src/blitz-client.ts @@ -7,5 +7,14 @@ export const authConfig = { } export const { withBlitz } = setupBlitzClient({ - plugins: [AuthClientPlugin(authConfig), BlitzRpcPlugin({})], + plugins: [ + AuthClientPlugin(authConfig), + BlitzRpcPlugin({ + reactQueryOptions: { + queries: { + refetchOnWindowFocus: false, + }, + }, + }), + ], }) diff --git a/src/pages/projects/[projectId]/tasks/new.tsx b/src/pages/projects/[projectId]/tasks/new.tsx index bc3ecc2b..d9bcf401 100644 --- a/src/pages/projects/[projectId]/tasks/new.tsx +++ b/src/pages/projects/[projectId]/tasks/new.tsx @@ -15,6 +15,135 @@ import Link from "next/link" import { InformationCircleIcon } from "@heroicons/react/24/outline" import { Tooltip } from "react-tooltip" +const mapTaskToInitialValues = (task: any) => { + if (!task) return undefined + + const initial: any = {} + + // Only copy simple text/date/ids + if (typeof task.name === "string" && task.name.trim()) initial.name = `${task.name} (Copy)` + if ("description" in task) initial.description = task.description ?? null + if ("milestoneId" in task) initial.milestoneId = task.milestoneId ?? null + if ("deadline" in task && task.deadline) initial.deadline = new Date(task.deadline) + if ("formVersionId" in task) initial.formVersionId = task.formVersionId ?? null + if ("startDate" in task && task.startDate) initial.startDate = new Date(task.startDate) + if ("containerId" in task) initial.containerId = task.containerId ?? null + if ("anonymous" in task) initial.anonymous = task.anonymous ?? false + + // Map contributors/teams from assignedMembers if present (kept minimal) + if (Array.isArray((task as any).assignedMembers)) { + const assigned = (task as any).assignedMembers as any[] + const contributors: number[] = [] + const teams: number[] = [] + for (const m of assigned) { + const id = typeof m?.id === "number" ? m.id : undefined + const usersLen = Array.isArray(m?.users) ? m.users.length : 0 + if (typeof id === "number") { + if (usersLen > 1) teams.push(id) + else contributors.push(id) + } + } + if (contributors.length) initial.projectMembersId = contributors + if (teams.length) initial.teamsId = teams + } + + // Map roles if included + if (Array.isArray((task as any).roles)) { + const rids = (task as any).roles + .map((r: any) => (typeof r?.id === "number" ? r.id : undefined)) + .filter((n: any) => typeof n === "number") + if (rids.length) initial.rolesId = rids + } + + // Copy simple numeric ID arrays (no relation includes) + const toNumArray = (arr: any) => + Array.isArray(arr) + ? arr + .map((v) => (v == null ? v : Number(v))) + .filter((v) => typeof v === "number" && !Number.isNaN(v)) + : undefined + + const roleIds = toNumArray((task as any).rolesId) + if (roleIds && roleIds.length) initial.rolesId = roleIds + + const memberIds = toNumArray((task as any).projectMembersId) + if (memberIds && memberIds.length) initial.projectMembersId = memberIds + + const teamIds = toNumArray((task as any).teamsId) + if (teamIds && teamIds.length) initial.teamsId = teamIds + + // Copy tags in UI shape expected by the tag input ({ id, text }) + if (Array.isArray((task as any).tags)) { + const src = (task as any).tags as any[] + const uiTags = src + .map((t) => { + if (!t) return undefined + if (typeof t === "object") { + if ("id" in t && "text" in t && typeof t.id === "string" && typeof t.text === "string") { + return { id: t.id, text: t.text } + } + if ( + "key" in t && + "value" in t && + typeof (t as any).key === "string" && + typeof (t as any).value === "string" + ) { + return { id: (t as any).key, text: (t as any).value } + } + } + if (typeof t === "string") return { id: t, text: t } + return undefined + }) + .filter(Boolean) + if (uiTags.length) initial.tags = uiTags as { id: string; text: string }[] + } + + return initial +} + +const TaskFormWrapper = ({ projectId, onSubmit, onCancel, schema }: any) => { + const router = useRouter() + const copyFromTaskIdParam = router.query.copyFromTaskId + const copyFromTaskId = + typeof copyFromTaskIdParam === "string" + ? parseInt(copyFromTaskIdParam, 10) + : Array.isArray(copyFromTaskIdParam) + ? parseInt(copyFromTaskIdParam[0]!, 10) + : undefined + + const [sourceTask] = useQuery( + getTask, + { + where: { id: copyFromTaskId ?? -1 }, + include: { + assignedMembers: { include: { users: { select: { id: true } } } }, + roles: { select: { id: true } }, + }, + }, + { + enabled: Boolean(copyFromTaskId), + suspense: false, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + } + ) + + const initialValues = mapTaskToInitialValues(sourceTask) + + return ( + + ) +} + const NewTaskPage = () => { const router = useRouter() const [createTaskMutation] = useMutation(createTask) @@ -61,141 +190,6 @@ const NewTaskPage = () => { } } - const mapTaskToInitialValues = (task: any) => { - if (!task) return undefined - - const initial: any = {} - - // Only copy simple text/date/ids - if (typeof task.name === "string" && task.name.trim()) initial.name = `${task.name} (Copy)` - if ("description" in task) initial.description = task.description ?? null - if ("milestoneId" in task) initial.milestoneId = task.milestoneId ?? null - if ("deadline" in task && task.deadline) initial.deadline = new Date(task.deadline) - if ("formVersionId" in task) initial.formVersionId = task.formVersionId ?? null - if ("startDate" in task && task.startDate) initial.startDate = new Date(task.startDate) - if ("containerId" in task) initial.containerId = task.containerId ?? null - if ("anonymous" in task) initial.anonymous = task.anonymous ?? false - - // Map contributors/teams from assignedMembers if present (kept minimal) - if (Array.isArray((task as any).assignedMembers)) { - const assigned = (task as any).assignedMembers as any[] - const contributors: number[] = [] - const teams: number[] = [] - for (const m of assigned) { - const id = typeof m?.id === "number" ? m.id : undefined - const usersLen = Array.isArray(m?.users) ? m.users.length : 0 - if (typeof id === "number") { - if (usersLen > 1) teams.push(id) - else contributors.push(id) - } - } - if (contributors.length) initial.projectMembersId = contributors - if (teams.length) initial.teamsId = teams - } - - // Map roles if included - if (Array.isArray((task as any).roles)) { - const rids = (task as any).roles - .map((r: any) => (typeof r?.id === "number" ? r.id : undefined)) - .filter((n: any) => typeof n === "number") - if (rids.length) initial.rolesId = rids - } - - // Copy simple numeric ID arrays (no relation includes) - const toNumArray = (arr: any) => - Array.isArray(arr) - ? arr - .map((v) => (v == null ? v : Number(v))) - .filter((v) => typeof v === "number" && !Number.isNaN(v)) - : undefined - - const roleIds = toNumArray((task as any).rolesId) - if (roleIds && roleIds.length) initial.rolesId = roleIds - - const memberIds = toNumArray((task as any).projectMembersId) - if (memberIds && memberIds.length) initial.projectMembersId = memberIds - - const teamIds = toNumArray((task as any).teamsId) - if (teamIds && teamIds.length) initial.teamsId = teamIds - - // Copy tags in UI shape expected by the tag input ({ id, text }) - if (Array.isArray((task as any).tags)) { - const src = (task as any).tags as any[] - const uiTags = src - .map((t) => { - if (!t) return undefined - if (typeof t === "object") { - if ( - "id" in t && - "text" in t && - typeof t.id === "string" && - typeof t.text === "string" - ) { - return { id: t.id, text: t.text } - } - if ( - "key" in t && - "value" in t && - typeof (t as any).key === "string" && - typeof (t as any).value === "string" - ) { - return { id: (t as any).key, text: (t as any).value } - } - } - if (typeof t === "string") return { id: t, text: t } - return undefined - }) - .filter(Boolean) - if (uiTags.length) initial.tags = uiTags as { id: string; text: string }[] - } - - return initial - } - - // Wrapper to handle copyFromTaskId and fetch the source task if needed - const TaskFormWrapper = ({ projectId, onSubmit, onCancel, schema }: any) => { - const router = useRouter() - const copyFromTaskIdParam = router.query.copyFromTaskId - const copyFromTaskId = - typeof copyFromTaskIdParam === "string" - ? parseInt(copyFromTaskIdParam, 10) - : Array.isArray(copyFromTaskIdParam) - ? parseInt(copyFromTaskIdParam[0]!, 10) - : undefined - - const [sourceTask] = useQuery( - getTask, - { - where: { id: copyFromTaskId ?? -1 }, - include: { - assignedMembers: { include: { users: { select: { id: true } } } }, - roles: { select: { id: true } }, - }, - }, - { - enabled: Boolean(copyFromTaskId), - suspense: false, - refetchOnWindowFocus: false, - refetchOnReconnect: false, - } - ) - - const initialValues = mapTaskToInitialValues(sourceTask) - - return ( - - ) - } - return ( // @ts-expect-error children are clearly passed below