@@ -1,4 +1,4 @@ | |||||
import CustomerDetail from "@/components/CustomerDetail"; | |||||
import CustomerSave from "@/components/CustomerSave"; | |||||
// import { preloadAllTasks } from "@/app/api/tasks"; | // import { preloadAllTasks } from "@/app/api/tasks"; | ||||
import CreateTaskTemplate from "@/components/CreateTaskTemplate"; | import CreateTaskTemplate from "@/components/CreateTaskTemplate"; | ||||
import { I18nProvider, getServerI18n } from "@/i18n"; | import { I18nProvider, getServerI18n } from "@/i18n"; | ||||
@@ -16,7 +16,7 @@ const CreateCustomer: React.FC = async () => { | |||||
<> | <> | ||||
<Typography variant="h4">{t("Create Customer")}</Typography> | <Typography variant="h4">{t("Create Customer")}</Typography> | ||||
<I18nProvider namespaces={["customer", "common"]}> | <I18nProvider namespaces={["customer", "common"]}> | ||||
<CustomerDetail /> | |||||
<CustomerSave /> | |||||
</I18nProvider> | </I18nProvider> | ||||
</> | </> | ||||
); | ); | ||||
@@ -1,5 +1,5 @@ | |||||
import { fetchAllSubsidiaries, preloadAllCustomers } from "@/app/api/customer"; | import { fetchAllSubsidiaries, preloadAllCustomers } from "@/app/api/customer"; | ||||
import CustomerDetail from "@/components/CustomerDetail"; | |||||
import CustomerSave from "@/components/CustomerSave"; | |||||
// import { preloadAllTasks } from "@/app/api/tasks"; | // import { preloadAllTasks } from "@/app/api/tasks"; | ||||
import CreateTaskTemplate from "@/components/CreateTaskTemplate"; | import CreateTaskTemplate from "@/components/CreateTaskTemplate"; | ||||
import { I18nProvider, getServerI18n } from "@/i18n"; | import { I18nProvider, getServerI18n } from "@/i18n"; | ||||
@@ -18,7 +18,7 @@ const EditCustomer: React.FC = async () => { | |||||
<> | <> | ||||
<Typography variant="h4">{t("Edit Customer")}</Typography> | <Typography variant="h4">{t("Edit Customer")}</Typography> | ||||
<I18nProvider namespaces={["customer", "common"]}> | <I18nProvider namespaces={["customer", "common"]}> | ||||
<CustomerDetail /> | |||||
<CustomerSave /> | |||||
</I18nProvider> | </I18nProvider> | ||||
</> | </> | ||||
); | ); | ||||
@@ -3,6 +3,7 @@ import CreateTaskTemplate from "@/components/CreateTaskTemplate"; | |||||
import { getServerI18n } from "@/i18n"; | import { getServerI18n } from "@/i18n"; | ||||
import Typography from "@mui/material/Typography"; | import Typography from "@mui/material/Typography"; | ||||
import { Metadata } from "next"; | import { Metadata } from "next"; | ||||
import { I18nProvider } from "@/i18n"; | |||||
export const metadata: Metadata = { | export const metadata: Metadata = { | ||||
title: "Create Task Template", | title: "Create Task Template", | ||||
@@ -15,7 +16,9 @@ const Projects: React.FC = async () => { | |||||
return ( | return ( | ||||
<> | <> | ||||
<Typography variant="h4">{t("Create Task Template")}</Typography> | <Typography variant="h4">{t("Create Task Template")}</Typography> | ||||
<CreateTaskTemplate /> | |||||
<I18nProvider namespaces={["tasks", "common"]}> | |||||
<CreateTaskTemplate /> | |||||
</I18nProvider> | |||||
</> | </> | ||||
); | ); | ||||
}; | }; | ||||
@@ -0,0 +1,26 @@ | |||||
import { preloadAllTasks } from "@/app/api/tasks"; | |||||
import CreateTaskTemplate from "@/components/CreateTaskTemplate"; | |||||
import { getServerI18n } from "@/i18n"; | |||||
import Typography from "@mui/material/Typography"; | |||||
import { Metadata } from "next"; | |||||
import { I18nProvider } from "@/i18n"; | |||||
export const metadata: Metadata = { | |||||
title: "Edit Task Template", | |||||
}; | |||||
const TaskTemplates: React.FC = async () => { | |||||
const { t } = await getServerI18n("tasks"); | |||||
preloadAllTasks(); | |||||
return ( | |||||
<> | |||||
<Typography variant="h4">{t("Edit Task Template")}</Typography> | |||||
<I18nProvider namespaces={["tasks", "common"]}> | |||||
<CreateTaskTemplate /> | |||||
</I18nProvider> | |||||
</> | |||||
); | |||||
}; | |||||
export default TaskTemplates; |
@@ -8,13 +8,14 @@ import Typography from "@mui/material/Typography"; | |||||
import { Metadata } from "next"; | import { Metadata } from "next"; | ||||
import Link from "next/link"; | import Link from "next/link"; | ||||
import { Suspense } from "react"; | import { Suspense } from "react"; | ||||
import { I18nProvider } from "@/i18n"; | |||||
export const metadata: Metadata = { | export const metadata: Metadata = { | ||||
title: "Tasks", | title: "Tasks", | ||||
}; | }; | ||||
const TaskTemplates: React.FC = async () => { | const TaskTemplates: React.FC = async () => { | ||||
const { t } = await getServerI18n("projects"); | |||||
const { t } = await getServerI18n("tasks"); | |||||
preloadTaskTemplates(); | preloadTaskTemplates(); | ||||
return ( | return ( | ||||
@@ -34,12 +35,14 @@ const TaskTemplates: React.FC = async () => { | |||||
LinkComponent={Link} | LinkComponent={Link} | ||||
href="/tasks/create" | href="/tasks/create" | ||||
> | > | ||||
{t("Create Template")} | |||||
{t("Create Task Template")} | |||||
</Button> | </Button> | ||||
</Stack> | </Stack> | ||||
<Suspense fallback={<TaskTemplateSearch.Loading />}> | |||||
<TaskTemplateSearch /> | |||||
</Suspense> | |||||
<I18nProvider namespaces={["tasks", "common"]}> | |||||
<Suspense fallback={<TaskTemplateSearch.Loading />}> | |||||
<TaskTemplateSearch /> | |||||
</Suspense> | |||||
</I18nProvider> | |||||
</> | </> | ||||
); | ); | ||||
}; | }; | ||||
@@ -1,6 +1,6 @@ | |||||
"use server"; | "use server"; | ||||
import { serverFetchJson } from "@/app/utils/fetchUtil"; | |||||
import { serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; | |||||
import { BASE_API_URL } from "@/config/api"; | import { BASE_API_URL } from "@/config/api"; | ||||
import { TaskTemplate } from "."; | import { TaskTemplate } from "."; | ||||
import { revalidateTag } from "next/cache"; | import { revalidateTag } from "next/cache"; | ||||
@@ -9,11 +9,13 @@ export interface NewTaskTemplateFormInputs { | |||||
code: string; | code: string; | ||||
name: string; | name: string; | ||||
taskIds: number[]; | taskIds: number[]; | ||||
id: number | null; | |||||
} | } | ||||
export const saveTaskTemplate = async (data: NewTaskTemplateFormInputs) => { | export const saveTaskTemplate = async (data: NewTaskTemplateFormInputs) => { | ||||
const newTaskTemplate = await serverFetchJson<TaskTemplate>( | const newTaskTemplate = await serverFetchJson<TaskTemplate>( | ||||
`${BASE_API_URL}/tasks/templates/new`, | |||||
`${BASE_API_URL}/tasks/templates/save`, | |||||
{ | { | ||||
method: "POST", | method: "POST", | ||||
body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
@@ -25,3 +27,27 @@ export const saveTaskTemplate = async (data: NewTaskTemplateFormInputs) => { | |||||
return newTaskTemplate; | return newTaskTemplate; | ||||
}; | }; | ||||
export const fetchTaskTemplate = async (id: number) => { | |||||
const taskTemplate = await serverFetchJson<TaskTemplate>( | |||||
`${BASE_API_URL}/tasks/templates/${id}`, | |||||
{ | |||||
method: "GET", | |||||
headers: { "Content-Type": "application/json" }, | |||||
}, | |||||
); | |||||
return taskTemplate; | |||||
}; | |||||
export const deleteTaskTemplate = async (id: number) => { | |||||
const taskTemplate = await serverFetchWithNoContent( | |||||
`${BASE_API_URL}/tasks/templates/${id}`, | |||||
{ | |||||
method: "DELETE", | |||||
headers: { "Content-Type": "application/json" }, | |||||
}, | |||||
); | |||||
return taskTemplate | |||||
}; |
@@ -10,15 +10,17 @@ import TransferList from "../TransferList"; | |||||
import Button from "@mui/material/Button"; | import Button from "@mui/material/Button"; | ||||
import Check from "@mui/icons-material/Check"; | import Check from "@mui/icons-material/Check"; | ||||
import Close from "@mui/icons-material/Close"; | import Close from "@mui/icons-material/Close"; | ||||
import { useRouter } from "next/navigation"; | |||||
import { useRouter, useSearchParams } from "next/navigation"; | |||||
import React from "react"; | import React from "react"; | ||||
import Stack from "@mui/material/Stack"; | import Stack from "@mui/material/Stack"; | ||||
import { Task } from "@/app/api/tasks"; | import { Task } from "@/app/api/tasks"; | ||||
import { | import { | ||||
NewTaskTemplateFormInputs, | NewTaskTemplateFormInputs, | ||||
fetchTaskTemplate, | |||||
saveTaskTemplate, | saveTaskTemplate, | ||||
} from "@/app/api/tasks/actions"; | } from "@/app/api/tasks/actions"; | ||||
import { SubmitHandler, useForm } from "react-hook-form"; | |||||
import { SubmitHandler, useFieldArray, useForm } from "react-hook-form"; | |||||
import { errorDialog, submitDialog, successDialog } from "../Swal/CustomAlerts"; | |||||
interface Props { | interface Props { | ||||
tasks: Task[]; | tasks: Task[]; | ||||
@@ -27,6 +29,7 @@ interface Props { | |||||
const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => { | const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => { | ||||
const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
const searchParams = useSearchParams() | |||||
const router = useRouter(); | const router = useRouter(); | ||||
const handleCancel = () => { | const handleCancel = () => { | ||||
router.back(); | router.back(); | ||||
@@ -49,6 +52,7 @@ const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => { | |||||
handleSubmit, | handleSubmit, | ||||
setValue, | setValue, | ||||
watch, | watch, | ||||
resetField, | |||||
formState: { errors, isSubmitting }, | formState: { errors, isSubmitting }, | ||||
} = useForm<NewTaskTemplateFormInputs>({ defaultValues: { taskIds: [] } }); | } = useForm<NewTaskTemplateFormInputs>({ defaultValues: { taskIds: [] } }); | ||||
@@ -57,12 +61,56 @@ const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => { | |||||
return items.filter((item) => currentTaskIds.includes(item.id)); | return items.filter((item) => currentTaskIds.includes(item.id)); | ||||
}, [currentTaskIds, items]); | }, [currentTaskIds, items]); | ||||
const [refTaskTemplate, setRefTaskTemplate] = React.useState<NewTaskTemplateFormInputs>() | |||||
const id = searchParams.get('id') | |||||
const fetchCurrentTaskTemplate = async () => { | |||||
try { | |||||
const taskTemplate = await fetchTaskTemplate(parseInt(id!!)) | |||||
const defaultValues = { | |||||
id: parseInt(id!!), | |||||
code: taskTemplate.code ?? null, | |||||
name: taskTemplate.name ?? null, | |||||
taskIds: taskTemplate.tasks.map(task => task.id) ?? [], | |||||
} | |||||
setRefTaskTemplate(defaultValues) | |||||
} catch (e) { | |||||
console.log(e) | |||||
} | |||||
} | |||||
React.useLayoutEffect(() => { | |||||
if (id !== null && parseInt(id) > 0) fetchCurrentTaskTemplate() | |||||
}, [id]) | |||||
React.useEffect(() => { | |||||
if (refTaskTemplate) { | |||||
setValue("taskIds", refTaskTemplate.taskIds) | |||||
resetField("code", { defaultValue: refTaskTemplate.code }) | |||||
resetField("name", { defaultValue: refTaskTemplate.name }) | |||||
setValue("id", refTaskTemplate.id) | |||||
} | |||||
}, [refTaskTemplate]) | |||||
const onSubmit: SubmitHandler<NewTaskTemplateFormInputs> = React.useCallback( | const onSubmit: SubmitHandler<NewTaskTemplateFormInputs> = React.useCallback( | ||||
async (data) => { | async (data) => { | ||||
try { | try { | ||||
setServerError(""); | setServerError(""); | ||||
await saveTaskTemplate(data); | |||||
router.replace("/tasks"); | |||||
submitDialog(async () => { | |||||
const response = await saveTaskTemplate(data); | |||||
if (response?.id !== null && response?.id !== undefined && response?.id > 0) { | |||||
successDialog(t("Submit Success"), t).then(() => { | |||||
router.replace("/tasks"); | |||||
}) | |||||
} else { | |||||
errorDialog(t("Submit Fail"), t).then(() => { | |||||
return false | |||||
}) | |||||
} | |||||
}, t) | |||||
} catch (e) { | } catch (e) { | ||||
setServerError(t("An error has occurred. Please try again later.")); | setServerError(t("An error has occurred. Please try again later.")); | ||||
} | } | ||||
@@ -71,72 +119,77 @@ const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => { | |||||
); | ); | ||||
return ( | return ( | ||||
<Stack component="form" onSubmit={handleSubmit(onSubmit)} gap={2}> | |||||
<Card> | |||||
<CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}> | |||||
<Typography variant="overline">{t("Task List Setup")}</Typography> | |||||
<Grid | |||||
container | |||||
spacing={2} | |||||
columns={{ xs: 6, sm: 12 }} | |||||
marginBlockEnd={1} | |||||
> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("Task Template Code")} | |||||
fullWidth | |||||
{...register("code", { | |||||
required: t("Task template code is required"), | |||||
})} | |||||
error={Boolean(errors.code?.message)} | |||||
helperText={errors.code?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("Task Template Name")} | |||||
fullWidth | |||||
{...register("name", { | |||||
required: t("Task template name is required"), | |||||
})} | |||||
error={Boolean(errors.name?.message)} | |||||
helperText={errors.name?.message} | |||||
<> | |||||
{ | |||||
(id === null || refTaskTemplate !== undefined) && <Stack component="form" onSubmit={handleSubmit(onSubmit)} gap={2}> | |||||
<Card> | |||||
<CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}> | |||||
<Typography variant="overline">{t("Task List Setup")}</Typography> | |||||
<Grid | |||||
container | |||||
spacing={2} | |||||
columns={{ xs: 6, sm: 12 }} | |||||
marginBlockEnd={1} | |||||
> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("Task Template Code")} | |||||
fullWidth | |||||
{...register("code", { | |||||
required: t("Task template code is required"), | |||||
})} | |||||
error={Boolean(errors.code?.message)} | |||||
helperText={errors.code?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("Task Template Name")} | |||||
fullWidth | |||||
{...register("name", { | |||||
required: t("Task template name is required"), | |||||
})} | |||||
error={Boolean(errors.name?.message)} | |||||
helperText={errors.name?.message} | |||||
/> | |||||
</Grid> | |||||
</Grid> | |||||
<TransferList | |||||
allItems={items} | |||||
selectedItems={selectedItems} | |||||
onChange={(selectedTasks) => { | |||||
setValue( | |||||
"taskIds", | |||||
selectedTasks.map((item) => item.id), | |||||
); | |||||
}} | |||||
allItemsLabel={t("Task Pool")} | |||||
selectedItemsLabel={t("Task List Template")} | |||||
/> | /> | ||||
</Grid> | |||||
</Grid> | |||||
<TransferList | |||||
allItems={items} | |||||
selectedItems={selectedItems} | |||||
onChange={(selectedTasks) => { | |||||
setValue( | |||||
"taskIds", | |||||
selectedTasks.map((item) => item.id), | |||||
); | |||||
}} | |||||
allItemsLabel={t("Task Pool")} | |||||
selectedItemsLabel={t("Task List Template")} | |||||
/> | |||||
</CardContent> | |||||
</Card> | |||||
{serverError && ( | |||||
<Typography variant="body2" color="error" alignSelf="flex-end"> | |||||
{serverError} | |||||
</Typography> | |||||
)} | |||||
<Stack direction="row" justifyContent="flex-end" gap={1}> | |||||
<Button variant="outlined" startIcon={<Close />} onClick={handleCancel}> | |||||
{t("Cancel")} | |||||
</Button> | |||||
<Button | |||||
variant="contained" | |||||
startIcon={<Check />} | |||||
type="submit" | |||||
disabled={isSubmitting} | |||||
> | |||||
{t("Confirm")} | |||||
</Button> | |||||
</Stack> | |||||
</Stack> | |||||
</CardContent> | |||||
</Card> | |||||
{ | |||||
serverError && ( | |||||
<Typography variant="body2" color="error" alignSelf="flex-end"> | |||||
{serverError} | |||||
</Typography> | |||||
) | |||||
} | |||||
<Stack direction="row" justifyContent="flex-end" gap={1}> | |||||
<Button variant="outlined" startIcon={<Close />} onClick={handleCancel}> | |||||
{t("Cancel")} | |||||
</Button> | |||||
<Button | |||||
variant="contained" | |||||
startIcon={<Check />} | |||||
type="submit" | |||||
disabled={isSubmitting} | |||||
> | |||||
{t("Confirm")} | |||||
</Button> | |||||
</Stack> | |||||
</Stack >} | |||||
</> | |||||
); | ); | ||||
}; | }; | ||||
@@ -1 +0,0 @@ | |||||
export { default } from "./CustomerDetailWrapper"; |
@@ -42,7 +42,7 @@ const hasErrorsInTab = ( | |||||
} | } | ||||
}; | }; | ||||
const CustomerDetail: React.FC<Props> = ({ | |||||
const CustomerSave: React.FC<Props> = ({ | |||||
subsidiaries, | subsidiaries, | ||||
customerTypes, | customerTypes, | ||||
}) => { | }) => { | ||||
@@ -277,4 +277,4 @@ const CustomerDetail: React.FC<Props> = ({ | |||||
); | ); | ||||
}; | }; | ||||
export default CustomerDetail; | |||||
export default CustomerSave; |
@@ -3,7 +3,7 @@ | |||||
// import { fetchProjectCategories } from "@/app/api/projects"; | // import { fetchProjectCategories } from "@/app/api/projects"; | ||||
// import { fetchTeamLeads } from "@/app/api/staff"; | // import { fetchTeamLeads } from "@/app/api/staff"; | ||||
import { fetchCustomerTypes, fetchAllSubsidiaries } from "@/app/api/customer"; | import { fetchCustomerTypes, fetchAllSubsidiaries } from "@/app/api/customer"; | ||||
import CustomerDetail from "./CustomerDetail"; | |||||
import CustomerSave from "./CustomerSave"; | |||||
// type Props = { | // type Props = { | ||||
// params: { | // params: { | ||||
@@ -11,7 +11,7 @@ import CustomerDetail from "./CustomerDetail"; | |||||
// }; | // }; | ||||
// }; | // }; | ||||
const CustomerDetailWrapper: React.FC = async () => { | |||||
const CustomerSaveWrapper: React.FC = async () => { | |||||
// const { params } = props | // const { params } = props | ||||
// console.log(params) | // console.log(params) | ||||
const [subsidiaries, customerTypes] = | const [subsidiaries, customerTypes] = | ||||
@@ -21,8 +21,8 @@ const CustomerDetailWrapper: React.FC = async () => { | |||||
]); | ]); | ||||
return ( | return ( | ||||
<CustomerDetail subsidiaries={subsidiaries} customerTypes={customerTypes} /> | |||||
<CustomerSave subsidiaries={subsidiaries} customerTypes={customerTypes} /> | |||||
); | ); | ||||
}; | }; | ||||
export default CustomerDetailWrapper; | |||||
export default CustomerSaveWrapper; |
@@ -0,0 +1 @@ | |||||
export { default } from "./CustomerSaveWrapper"; |
@@ -68,7 +68,7 @@ const StaffSearch: React.FC<Props> = ({ staff }) => { | |||||
const deleteClick = useCallback((staff: StaffResult) => { | const deleteClick = useCallback((staff: StaffResult) => { | ||||
deleteDialog(async () => { | deleteDialog(async () => { | ||||
await deleteStaff(staff.id); | await deleteStaff(staff.id); | ||||
successDialog("Delete Success", t); | |||||
successDialog(t("Delete Success"), t); | |||||
setFilteredStaff((prev) => prev.filter((obj) => obj.id !== staff.id)); | setFilteredStaff((prev) => prev.filter((obj) => obj.id !== staff.id)); | ||||
}, t); | }, t); | ||||
}, []); | }, []); | ||||
@@ -1,7 +1,7 @@ | |||||
import { fetchAllCustomers, fetchSubsidiaryTypes } from "@/app/api/subsidiary"; | import { fetchAllCustomers, fetchSubsidiaryTypes } from "@/app/api/subsidiary"; | ||||
import SubsidiaryDetail from "./SubsidiaryDetail"; | import SubsidiaryDetail from "./SubsidiaryDetail"; | ||||
const CustomerDetailWrapper: React.FC = async () => { | |||||
const CustomerSaveWrapper: React.FC = async () => { | |||||
const [customers, subsidiaryTypes] = | const [customers, subsidiaryTypes] = | ||||
await Promise.all([ | await Promise.all([ | ||||
fetchAllCustomers(), | fetchAllCustomers(), | ||||
@@ -13,4 +13,4 @@ const CustomerDetailWrapper: React.FC = async () => { | |||||
); | ); | ||||
}; | }; | ||||
export default CustomerDetailWrapper; | |||||
export default CustomerSaveWrapper; |
@@ -46,7 +46,7 @@ const SubsidiarySearch: React.FC<Props> = ({ subsidiaries }) => { | |||||
deleteDialog(async() => { | deleteDialog(async() => { | ||||
await deleteSubsidiary(subsidiary.id) | await deleteSubsidiary(subsidiary.id) | ||||
successDialog("Delete Success", t) | |||||
successDialog(t("Delete Success"), t) | |||||
setFilteredSubsidiaries((prev) => prev.filter((obj) => obj.id !== subsidiary.id)) | setFilteredSubsidiaries((prev) => prev.filter((obj) => obj.id !== subsidiary.id)) | ||||
}, t) | }, t) | ||||
@@ -6,6 +6,10 @@ import SearchBox, { Criterion } from "../SearchBox"; | |||||
import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
import SearchResults, { Column } from "../SearchResults"; | import SearchResults, { Column } from "../SearchResults"; | ||||
import EditNote from "@mui/icons-material/EditNote"; | import EditNote from "@mui/icons-material/EditNote"; | ||||
import { useRouter, useSearchParams } from "next/navigation"; | |||||
import DeleteIcon from '@mui/icons-material/Delete'; | |||||
import { deleteDialog, successDialog } from "../Swal/CustomAlerts"; | |||||
import { deleteTaskTemplate } from "@/app/api/tasks/actions"; | |||||
interface Props { | interface Props { | ||||
taskTemplates: TaskTemplate[]; | taskTemplates: TaskTemplate[]; | ||||
@@ -16,6 +20,8 @@ type SearchParamNames = keyof SearchQuery; | |||||
const TaskTemplateSearch: React.FC<Props> = ({ taskTemplates }) => { | const TaskTemplateSearch: React.FC<Props> = ({ taskTemplates }) => { | ||||
const { t } = useTranslation("tasks"); | const { t } = useTranslation("tasks"); | ||||
const searchParams = useSearchParams() | |||||
const router = useRouter() | |||||
const [filteredTemplates, setFilteredTemplates] = useState(taskTemplates); | const [filteredTemplates, setFilteredTemplates] = useState(taskTemplates); | ||||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
@@ -30,7 +36,20 @@ const TaskTemplateSearch: React.FC<Props> = ({ taskTemplates }) => { | |||||
}, [taskTemplates]); | }, [taskTemplates]); | ||||
const onTaskClick = useCallback((taskTemplate: TaskTemplate) => { | const onTaskClick = useCallback((taskTemplate: TaskTemplate) => { | ||||
console.log(taskTemplate); | |||||
const params = new URLSearchParams(searchParams.toString()) | |||||
params.set("id", taskTemplate.id.toString()) | |||||
router.replace(`/tasks/edit?${params.toString()}`); | |||||
}, []); | |||||
const onDeleteClick = useCallback((taskTemplate: TaskTemplate) => { | |||||
deleteDialog(async () => { | |||||
await deleteTaskTemplate(taskTemplate.id) | |||||
successDialog(t("Delete Success"), t) | |||||
setFilteredTemplates((prev) => prev.filter((obj) => obj.id !== taskTemplate.id)) | |||||
}, t) | |||||
}, []); | }, []); | ||||
const columns = useMemo<Column<TaskTemplate>[]>( | const columns = useMemo<Column<TaskTemplate>[]>( | ||||
@@ -43,6 +62,13 @@ const TaskTemplateSearch: React.FC<Props> = ({ taskTemplates }) => { | |||||
}, | }, | ||||
{ name: "code", label: t("Task Template Code") }, | { name: "code", label: t("Task Template Code") }, | ||||
{ name: "name", label: t("Task Template Name") }, | { name: "name", label: t("Task Template Name") }, | ||||
{ | |||||
name: "id", | |||||
label: t("Delete"), | |||||
onClick: onDeleteClick, | |||||
buttonIcon: <DeleteIcon />, | |||||
color: "error" | |||||
}, | |||||
], | ], | ||||
[onTaskClick, t], | [onTaskClick, t], | ||||
); | ); | ||||
@@ -56,7 +56,7 @@ const TeamSearch: React.FC<Props> = ({ team }) => { | |||||
deleteDialog(async () => { | deleteDialog(async () => { | ||||
await deleteTeam(team.id); | await deleteTeam(team.id); | ||||
successDialog("Delete Success", t); | |||||
successDialog(t("Delete Success"), t); | |||||
setFilteredTeam((prev) => prev.filter((obj) => obj.id !== team.id)); | setFilteredTeam((prev) => prev.filter((obj) => obj.id !== team.id)); | ||||
}, t); | }, t); | ||||
@@ -109,7 +109,7 @@ const ItemList: React.FC<ItemListProps> = ({ | |||||
</ListItemIcon> | </ListItemIcon> | ||||
<Stack> | <Stack> | ||||
<Typography variant="subtitle2">{label}</Typography> | <Typography variant="subtitle2">{label}</Typography> | ||||
<Typography variant="caption">{`${checkedItems.length}/${items.length} selected`}</Typography> | |||||
<Typography variant="caption">{`${checkedItems.length}/${items.length} ${t("selected")}`}</Typography> | |||||
</Stack> | </Stack> | ||||
</Stack> | </Stack> | ||||
<Divider /> | <Divider /> | ||||
@@ -45,7 +45,7 @@ const UserSearch: React.FC<Props> = ({ users }) => { | |||||
deleteDialog(async () => { | deleteDialog(async () => { | ||||
await deleteUser(users.id); | await deleteUser(users.id); | ||||
successDialog("Delete Success", t); | |||||
successDialog(t("Delete Success"), t); | |||||
setFilteredUser((prev) => prev.filter((obj) => obj.id !== users.id)); | setFilteredUser((prev) => prev.filter((obj) => obj.id !== users.id)); | ||||
}, t); | }, t); | ||||
@@ -17,6 +17,8 @@ | |||||
"Do you want to delete?": "Do you want to delete", | "Do you want to delete?": "Do you want to delete", | ||||
"Delete Success": "Delete Success", | "Delete Success": "Delete Success", | ||||
"Details": "Details", | |||||
"Delete": "Delete", | |||||
"Search": "Search", | "Search": "Search", | ||||
"Search Criteria": "Search Criteria", | "Search Criteria": "Search Criteria", | ||||
"Cancel": "Cancel", | "Cancel": "Cancel", | ||||
@@ -0,0 +1,27 @@ | |||||
{ | |||||
"Task Template": "Task Template", | |||||
"Create Task Template": "Create Task Template", | |||||
"Edit Task Template": "Edit Task Template", | |||||
"Task Template Code": "Task Template Code", | |||||
"Task Template Name": "Task Template Name", | |||||
"Task List Setup": "Task List Setup", | |||||
"Task Pool": "Task Pool", | |||||
"Task List Template": "Task List Template", | |||||
"Task template code is required": "Task template code is required", | |||||
"Task template name is required": "Task template name is required", | |||||
"Do you want to submit?": "Do you want to submit?", | |||||
"Submit Success": "Submit Success", | |||||
"Submit Fail": "Submit Fail", | |||||
"Do you want to delete?": "Do you want to delete?", | |||||
"Delete Success": "Delete Success", | |||||
"selected": "selected", | |||||
"Details": "Details", | |||||
"Delete": "Delete", | |||||
"Cancel": "Cancel", | |||||
"Submit": "Submit", | |||||
"Confirm": "Confirm" | |||||
} |
@@ -15,6 +15,8 @@ | |||||
"Do you want to delete?": "你是否確認要刪除?", | "Do you want to delete?": "你是否確認要刪除?", | ||||
"Delete Success": "刪除成功", | "Delete Success": "刪除成功", | ||||
"Details": "詳情", | |||||
"Delete": "刪除", | |||||
"Search": "搜尋", | "Search": "搜尋", | ||||
"Search Criteria": "搜尋條件", | "Search Criteria": "搜尋條件", | ||||
"Cancel": "取消", | "Cancel": "取消", | ||||
@@ -0,0 +1,27 @@ | |||||
{ | |||||
"Task Template": "工作範本", | |||||
"Create Task Template": "建立工作範本", | |||||
"Edit Task Template": "編輯工作範本", | |||||
"Task Template Code": "工作範本編號", | |||||
"Task Template Name": "工作範本名稱", | |||||
"Task List Setup": "工作名單設置", | |||||
"Task Pool": "所有工作", | |||||
"Task List Template": "工作名單範本", | |||||
"Task template code is required": "需要工作範本編號", | |||||
"Task template name is required": "需要工作範本名稱", | |||||
"Do you want to submit?": "你是否確認要提交?", | |||||
"Submit Success": "提交成功", | |||||
"Submit Fail": "提交失敗", | |||||
"Do you want to delete?": "你是否確認要刪除?", | |||||
"Delete Success": "刪除成功", | |||||
"selected": "已選擇", | |||||
"Details": "詳情", | |||||
"Delete": "刪除", | |||||
"Cancel": "取消", | |||||
"Submit": "提交", | |||||
"Confirm": "確認" | |||||
} |