Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/blitz-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,14 @@ export const authConfig = {
}

export const { withBlitz } = setupBlitzClient({
plugins: [AuthClientPlugin(authConfig), BlitzRpcPlugin({})],
plugins: [
AuthClientPlugin(authConfig),
BlitzRpcPlugin({
reactQueryOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
}),
],
})
264 changes: 129 additions & 135 deletions src/pages/projects/[projectId]/tasks/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<TaskForm
className="flex flex-col"
projectId={projectId}
submitText="Create Task"
schema={schema}
onSubmit={onSubmit}
onCancel={onCancel}
cancelText="Cancel"
{...(initialValues ? { initialValues } : {})}
/>
)
}

const NewTaskPage = () => {
const router = useRouter()
const [createTaskMutation] = useMutation(createTask)
Expand Down Expand Up @@ -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 (
<TaskForm
className="flex flex-col"
projectId={projectId}
submitText="Create Task"
schema={schema}
onSubmit={onSubmit}
onCancel={onCancel}
cancelText="Cancel"
{...(initialValues ? { initialValues } : {})}
/>
)
}

return (
// @ts-expect-error children are clearly passed below
<Layout title="Create New Task">
Expand Down
Loading