update project update prosess in frontend, and add project validators

This commit is contained in:
juhanikat
2026-08-05 16:36:54 +03:00
parent 7143da32c1
commit 57eec7c149
3 changed files with 110 additions and 9 deletions
@@ -1,12 +1,20 @@
import { useMemo } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import { CircularProgress } from '@mui/material'
import { DetailView, TabType } from '../DetailView/DetailView'
import { CoordinatorTab } from './Tabs/CoordinatorTab'
import { useDeleteProjectMutation, useGetProjectDetailsQuery, useUpdateProjectMutation } from '@/redux/projectReducer'
import { useNotify } from '@/hooks/notification'
import { useUsersApi } from '@/hooks/useUsersApi'
import { mapProjectEditDataToUpdatePayload } from '@/api/projectsApi'
import {
UpdateProjectPayload,
useDeleteProjectMutation,
useGetProjectDetailsQuery,
useUpdateProjectMutation,
} from '@/redux/projectReducer'
import { ProjectPeople, RowState } from '@/shared/types'
import { CircularProgress } from '@mui/material'
import { DetailView, TabType } from '../DetailView/DetailView'
import { CoordinatorTab } from './Tabs/CoordinatorTab'
import type { EditDataType, ProjectDetailsType } from '@/shared/types'
import type { ValidationObject } from '@/shared/validators/validator'
import type { FetchBaseQueryError } from '@reduxjs/toolkit/query'
@@ -56,15 +64,54 @@ export const ProjectDetails = () => {
error: null,
})
const createProjectUpdatePayload = (editData: EditDataType<ProjectDetailsType>): UpdateProjectPayload | null => {
const userOption = users.find(user => user.initials === editData.contact)
if (!userOption) {
notify('Could not find selected coordinator.', 'error')
return null
}
const isRemoved = (member: EditDataType<ProjectPeople>) => {
const state = (member as EditDataType<ProjectPeople> & { rowState?: RowState }).rowState
return state === 'removed' || state === 'cancelled'
}
const memberUserIds = Array.from(
new Set(
(editData.now_proj_people ?? [])
.filter(member => !isRemoved(member))
.map(member => {
const userIdFromPeople = (member.com_people as { user_id?: number } | undefined)?.user_id
const userIdFromRelation = member.com_people?.user?.user_id
if (typeof userIdFromPeople === 'number') return userIdFromPeople
if (typeof userIdFromRelation === 'number') return userIdFromRelation
return users.find(user => user.initials === member.initials) ?? null
})
.filter((id): id is number => typeof id === 'number')
)
)
return {
pid: editData.pid!,
projectCode: editData.proj_code!,
projectName: editData.proj_name!,
coordinatorUserId: userOption.userId,
projectStatus: editData.proj_status!,
recordStatus: editData.proj_records!,
memberUserIds,
}
}
const onWrite = async (editData: EditDataType<ProjectDetailsType>) => {
if (!projectId) return
const payload = mapProjectEditDataToUpdatePayload(editData, users)
const payload = createProjectUpdatePayload(editData)
if (!payload) {
notify('Coordinator selection is required to save project changes.', 'error')
return
}
console.log(editData)
console.log(payload)
try {
await updateProject(payload).unwrap()
notify('Saved project successfully.')
@@ -9,8 +9,8 @@ export const CoordinatorTab = () => {
const projectInformation = [
['Project Id', textField('pid', { type: 'text', readonly: true, disabled: true })],
['Project Code', textField('proj_code')],
['Project Name', textField('proj_name')],
['Project Code', textField('proj_code', { trim: true })],
['Project Name', textField('proj_name', { trim: true })],
['Coordinator', <CoordinatorSelect key="coordinator-select" variant="detail" />],
[
'Project Status',
+54
View File
@@ -0,0 +1,54 @@
import { EditDataType, Project } from '../types'
import { Validators, validateFields, validator } from './validator'
/*
pid: number;
contact: string;
proj_code: string | null;
proj_name: string | null;
proj_status: string | null;
proj_records: boolean | null;
*/
const projectValidators: Validators<Partial<EditDataType<Project>>> = {
pid: {
name: 'Project Id',
required: true,
},
contact: {
name: 'Coordinator',
required: true,
},
proj_code: {
name: 'Project Code',
required: true,
},
proj_name: {
name: 'Project Name',
required: true,
},
proj_status: {
name: 'Project Status',
required: true,
asString: value => {
if (!['current', 'no_data', 'finished'].includes(value))
return 'Project Status must be one of the following: "current", "no_data", or "finished".'
return null
},
},
proj_records: {
name: 'Record Status',
required: true,
asString: value => {
if (!['public', 'private'].includes(value)) return 'Record Status must be either true or false.'
return null
},
},
}
export const validateProject = (editData: EditDataType<Project>, fieldName: keyof EditDataType<Project>) => {
return validator<EditDataType<Project>>(projectValidators, editData, fieldName)
}
export const validateProjectFields = (editData: Partial<EditDataType<Project>>) =>
validateFields<EditDataType<Project>>(projectValidators, editData)